xtb-api-python 0.5.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- xtb_api/__init__.py +70 -0
- xtb_api/__main__.py +154 -0
- xtb_api/auth/__init__.py +5 -0
- xtb_api/auth/auth_manager.py +321 -0
- xtb_api/auth/browser_auth.py +316 -0
- xtb_api/auth/cas_client.py +543 -0
- xtb_api/client.py +444 -0
- xtb_api/exceptions.py +56 -0
- xtb_api/grpc/__init__.py +25 -0
- xtb_api/grpc/client.py +329 -0
- xtb_api/grpc/proto.py +239 -0
- xtb_api/grpc/types.py +14 -0
- xtb_api/instruments.py +132 -0
- xtb_api/py.typed +0 -0
- xtb_api/types/__init__.py +6 -0
- xtb_api/types/enums.py +92 -0
- xtb_api/types/instrument.py +45 -0
- xtb_api/types/trading.py +139 -0
- xtb_api/types/websocket.py +164 -0
- xtb_api/utils.py +62 -0
- xtb_api/ws/__init__.py +3 -0
- xtb_api/ws/parsers.py +161 -0
- xtb_api/ws/ws_client.py +905 -0
- xtb_api_python-0.5.2.dist-info/METADATA +257 -0
- xtb_api_python-0.5.2.dist-info/RECORD +28 -0
- xtb_api_python-0.5.2.dist-info/WHEEL +4 -0
- xtb_api_python-0.5.2.dist-info/entry_points.txt +2 -0
- xtb_api_python-0.5.2.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xtb-api-python
|
|
3
|
+
Version: 0.5.2
|
|
4
|
+
Summary: Python port of unofficial XTB xStation5 API client
|
|
5
|
+
Project-URL: Homepage, https://github.com/liskeee/xtb-api-python
|
|
6
|
+
Project-URL: Repository, https://github.com/liskeee/xtb-api-python
|
|
7
|
+
Project-URL: Issues, https://github.com/liskeee/xtb-api-python/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/liskeee/xtb-api-python/blob/master/CHANGELOG.md
|
|
9
|
+
Author-email: Łukasz Lis <ll.lukasz.lis@gmail.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: api,trading,websocket,xstation5,xtb
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Framework :: AsyncIO
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.12
|
|
25
|
+
Requires-Dist: httpx>=0.27
|
|
26
|
+
Requires-Dist: playwright>=1.40
|
|
27
|
+
Requires-Dist: pydantic>=2.5
|
|
28
|
+
Requires-Dist: websockets>=13.0
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
33
|
+
Provides-Extra: totp
|
|
34
|
+
Requires-Dist: pyotp>=2.9.0; extra == 'totp'
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
[](https://pypi.org/project/xtb-api-python/)
|
|
38
|
+
[](https://pypi.org/project/xtb-api-python/)
|
|
39
|
+
[](https://github.com/liskeee/xtb-api-python/actions/workflows/ci.yml)
|
|
40
|
+
[](LICENSE)
|
|
41
|
+
|
|
42
|
+
# xtb-api-python
|
|
43
|
+
|
|
44
|
+
> **Unofficial** — Reverse-engineered from xStation5. Not affiliated with XTB. Use at your own risk.
|
|
45
|
+
|
|
46
|
+
Python client for the XTB xStation5 trading platform. Dead-simple API that handles all authentication, token refresh, and transport selection transparently.
|
|
47
|
+
|
|
48
|
+
## Features
|
|
49
|
+
|
|
50
|
+
- **Single Client** — One `XTBClient` handles everything, no mode selection needed
|
|
51
|
+
- **Auto Auth** — Full CAS login flow with automatic TGT/JWT refresh
|
|
52
|
+
- **2FA Support** — Automatic TOTP handling when `totp_secret` is provided
|
|
53
|
+
- **Real-time Data** — Live quotes, positions, balance via WebSocket push events
|
|
54
|
+
- **Trading** — Buy/sell market orders with SL/TP via gRPC-web
|
|
55
|
+
- **11,888+ Instruments** — Full symbol search with caching
|
|
56
|
+
- **Modern Python** — async/await, Pydantic models, strict typing, Python 3.12+
|
|
57
|
+
|
|
58
|
+
## Requirements
|
|
59
|
+
|
|
60
|
+
- Python **3.12 or 3.13**
|
|
61
|
+
- Chromium browser (installed via playwright — see post-install step below)
|
|
62
|
+
- An XTB trading account
|
|
63
|
+
|
|
64
|
+
## Install
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install xtb-api-python
|
|
68
|
+
|
|
69
|
+
# With automatic 2FA handling:
|
|
70
|
+
pip install "xtb-api-python[totp]"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Post-install setup (REQUIRED)
|
|
74
|
+
|
|
75
|
+
This library uses [Playwright](https://playwright.dev/python/) to authenticate with
|
|
76
|
+
XTB's servers (the REST login path is blocked by a WAF). **After** `pip install`,
|
|
77
|
+
you must download the Chromium binary:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
playwright install chromium
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Without this step, the first call to `client.connect()` will fail with a
|
|
84
|
+
`CASError("BROWSER_CHROMIUM_MISSING", ...)` and a pointer back here.
|
|
85
|
+
|
|
86
|
+
To verify your install is complete, run:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
python -m xtb_api doctor
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Development install
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pip install -e ".[dev,totp]"
|
|
96
|
+
playwright install chromium
|
|
97
|
+
pre-commit install
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Quick Start
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
import asyncio
|
|
104
|
+
from xtb_api import XTBClient
|
|
105
|
+
|
|
106
|
+
async def main():
|
|
107
|
+
client = XTBClient(
|
|
108
|
+
email="your@email.com",
|
|
109
|
+
password="your-password",
|
|
110
|
+
account_number=12345678,
|
|
111
|
+
totp_secret="BASE32SECRET", # optional, auto-handles 2FA
|
|
112
|
+
session_file="~/.xtb_session", # optional, persists auth across restarts
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
await client.connect()
|
|
116
|
+
|
|
117
|
+
# Account data
|
|
118
|
+
balance = await client.get_balance()
|
|
119
|
+
print(f"Balance: {balance.balance} {balance.currency}")
|
|
120
|
+
|
|
121
|
+
positions = await client.get_positions()
|
|
122
|
+
orders = await client.get_orders()
|
|
123
|
+
|
|
124
|
+
# Live quote
|
|
125
|
+
quote = await client.get_quote("EURUSD")
|
|
126
|
+
if quote:
|
|
127
|
+
print(f"Bid: {quote.bid}, Ask: {quote.ask}")
|
|
128
|
+
|
|
129
|
+
# Search instruments
|
|
130
|
+
results = await client.search_instrument("Apple")
|
|
131
|
+
|
|
132
|
+
# Trading (USE WITH CAUTION!)
|
|
133
|
+
result = await client.buy("AAPL.US", volume=1, stop_loss=150.0, take_profit=200.0)
|
|
134
|
+
print(f"Order: {result.order_id}")
|
|
135
|
+
|
|
136
|
+
await client.disconnect()
|
|
137
|
+
|
|
138
|
+
asyncio.run(main())
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Real-time Events
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
client.on("tick", lambda tick: print(f"{tick['symbol']}: {tick['bid']}/{tick['ask']}"))
|
|
145
|
+
client.on("position", lambda pos: print(f"Position update: {pos['symbol']}"))
|
|
146
|
+
|
|
147
|
+
await client.subscribe_ticks("EURUSD")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Advanced Trade Options
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from xtb_api import TradeOptions
|
|
154
|
+
|
|
155
|
+
# Simple: flat kwargs
|
|
156
|
+
await client.buy("EURUSD", volume=1, stop_loss=1.0850, take_profit=1.0950)
|
|
157
|
+
|
|
158
|
+
# Advanced: TradeOptions object
|
|
159
|
+
await client.sell("CIG.PL", volume=100, options=TradeOptions(
|
|
160
|
+
trailing_stop=50,
|
|
161
|
+
amount=1000.0, # amount-based sizing
|
|
162
|
+
))
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## API Reference
|
|
166
|
+
|
|
167
|
+
### `XTBClient`
|
|
168
|
+
|
|
169
|
+
| Method | Returns | Description |
|
|
170
|
+
|--------|---------|-------------|
|
|
171
|
+
| `connect()` | `None` | Connect and authenticate |
|
|
172
|
+
| `disconnect()` | `None` | Disconnect and clean up |
|
|
173
|
+
| `get_balance()` | `AccountBalance` | Account balance, equity, free margin |
|
|
174
|
+
| `get_positions()` | `list[Position]` | Open trading positions |
|
|
175
|
+
| `get_orders()` | `list[PendingOrder]` | Pending limit/stop orders |
|
|
176
|
+
| `get_quote(symbol)` | `Quote \| None` | Current bid/ask for a symbol |
|
|
177
|
+
| `search_instrument(query)` | `list[InstrumentSearchResult]` | Search instruments |
|
|
178
|
+
| `buy(symbol, volume, ...)` | `TradeResult` | Execute BUY order |
|
|
179
|
+
| `sell(symbol, volume, ...)` | `TradeResult` | Execute SELL order |
|
|
180
|
+
| `on(event, callback)` | `None` | Register event handler |
|
|
181
|
+
| `subscribe_ticks(symbol)` | `None` | Subscribe to real-time ticks |
|
|
182
|
+
|
|
183
|
+
### Constructor Parameters
|
|
184
|
+
|
|
185
|
+
| Parameter | Required | Default | Description |
|
|
186
|
+
|-----------|----------|---------|-------------|
|
|
187
|
+
| `email` | Yes | — | XTB account email |
|
|
188
|
+
| `password` | Yes | — | XTB account password |
|
|
189
|
+
| `account_number` | Yes | — | XTB account number |
|
|
190
|
+
| `totp_secret` | No | `""` | Base32 TOTP secret for auto 2FA |
|
|
191
|
+
| `session_file` | No | `None` | Path to persist auth session |
|
|
192
|
+
| `ws_url` | No | Real server | WebSocket endpoint URL |
|
|
193
|
+
| `endpoint` | No | `"meta1"` | Server endpoint name |
|
|
194
|
+
| `account_server` | No | `"XS-real1"` | gRPC account server |
|
|
195
|
+
| `auto_reconnect` | No | `True` | Auto-reconnect on disconnect |
|
|
196
|
+
|
|
197
|
+
### WebSocket URLs
|
|
198
|
+
|
|
199
|
+
| Environment | URL |
|
|
200
|
+
|-------------|-----|
|
|
201
|
+
| Real | `wss://api5reala.x-station.eu/v1/xstation` (default) |
|
|
202
|
+
| Demo | `wss://api5demoa.x-station.eu/v1/xstation` |
|
|
203
|
+
|
|
204
|
+
### Advanced: Direct Access
|
|
205
|
+
|
|
206
|
+
For advanced use cases, access the underlying clients:
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
# WebSocket client (always available)
|
|
210
|
+
ws = client.ws
|
|
211
|
+
|
|
212
|
+
# gRPC client (available after first trade)
|
|
213
|
+
grpc = client.grpc_client
|
|
214
|
+
|
|
215
|
+
# Auth manager
|
|
216
|
+
auth = client.auth
|
|
217
|
+
tgt = await auth.get_tgt()
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Architecture
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
XTBClient (public facade)
|
|
224
|
+
|
|
|
225
|
+
+-- AuthManager (shared auth session)
|
|
226
|
+
| +-- CASClient (REST + Playwright browser auth)
|
|
227
|
+
| +-- TGT cache (memory + disk)
|
|
228
|
+
|
|
|
229
|
+
+-- XTBWebSocketClient (quotes, positions, balance)
|
|
230
|
+
| +-- Auto-reconnect with fresh service tickets
|
|
231
|
+
|
|
|
232
|
+
+-- GrpcClient (trading, lazy-initialized)
|
|
233
|
+
+-- JWT auto-refresh from shared TGT
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## How Authentication Works
|
|
237
|
+
|
|
238
|
+
1. **Login** — REST CAS attempt, falls back to Playwright browser if WAF blocks
|
|
239
|
+
2. **TGT** — 8-hour token, cached in memory + optional session file
|
|
240
|
+
3. **Service Ticket** — Derived from TGT, used for WebSocket login
|
|
241
|
+
4. **JWT** — 5-minute token for gRPC trading, auto-refreshed from TGT
|
|
242
|
+
5. **2FA** — Automatic TOTP if `totp_secret` provided
|
|
243
|
+
|
|
244
|
+
All token refresh is transparent. If a TGT expires mid-session, the full auth chain re-runs automatically.
|
|
245
|
+
|
|
246
|
+
## Disclaimer
|
|
247
|
+
|
|
248
|
+
This is an **unofficial**, community-driven project. NOT affiliated with, endorsed by, or connected to XTB S.A.
|
|
249
|
+
|
|
250
|
+
- **Use at your own risk** — trading involves financial risk
|
|
251
|
+
- **No warranty** — provided "as is"
|
|
252
|
+
- **API stability** — XTB may change their internal APIs at any time
|
|
253
|
+
- **Always test on demo accounts first**
|
|
254
|
+
|
|
255
|
+
## License
|
|
256
|
+
|
|
257
|
+
MIT
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
xtb_api/__init__.py,sha256=4uuWQIVA508vYbb6_KOsyUXkWRIC3Jxv9vhCVcky8Q0,1581
|
|
2
|
+
xtb_api/__main__.py,sha256=r0Du6KYGst8U0l9dkLV55EwxqBFsQqwwPZ1wq5UdgZE,4688
|
|
3
|
+
xtb_api/client.py,sha256=DDDdQFrSLcwT3OlImam4s9lFiTbZ5M1a6pxA-iu30C4,17168
|
|
4
|
+
xtb_api/exceptions.py,sha256=Im69z0LPxhR6mV3XTrh99V8ai-hteczZJkhayjQC55Q,1522
|
|
5
|
+
xtb_api/instruments.py,sha256=GAfVtIX9siIkbyxRCi_cFWI9TWLoLnBm4zw-3_AzWQE,4857
|
|
6
|
+
xtb_api/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
xtb_api/utils.py,sha256=xpJ3QTfeCkMnhOu_YCdRq2KPL0hTMC7Y_wqvvCWLM4s,1781
|
|
8
|
+
xtb_api/auth/__init__.py,sha256=p9Devj_dJBgH6awKdUU4uJwBkZaYSz5v932SqEEWHY4,229
|
|
9
|
+
xtb_api/auth/auth_manager.py,sha256=JCViygItScN3Dpwzjxy-ZuywFB6r5fAYycg-HW9l_ss,12174
|
|
10
|
+
xtb_api/auth/browser_auth.py,sha256=Z9CkbcyZ_AyeFWVaRS3QlqTpC2st7_tSb3UMU5UMh6o,12383
|
|
11
|
+
xtb_api/auth/cas_client.py,sha256=f4Rs9LI8A1Y4wTJ1itOGS8cjwnfjAUT5o_Q8TFKplE0,20292
|
|
12
|
+
xtb_api/grpc/__init__.py,sha256=puaZSuPIJ8XWt29c02G95wfWFem5YPDa73Z3PgQI7sM,569
|
|
13
|
+
xtb_api/grpc/client.py,sha256=fdmkCVbZqLQgxrr7olWuPFvAmJdDVX2k-fzsCcO5IGE,11173
|
|
14
|
+
xtb_api/grpc/proto.py,sha256=jglStrhkWrKzEGO2PWXL2iTEm-wulFK99OijD2rQFKU,8753
|
|
15
|
+
xtb_api/grpc/types.py,sha256=178wH9tm1vge7D3O0trOIZCk9qmSzH0PAfiHfjUml8Y,298
|
|
16
|
+
xtb_api/types/__init__.py,sha256=XY4_GL07XDS_wo7iqHB-tsu3SCOm0s9dwg-kr62t6rA,236
|
|
17
|
+
xtb_api/types/enums.py,sha256=p-jzwyAevBFhzwO25Xh3EAIDmd6WMVuI5_I8yd3GvOQ,1837
|
|
18
|
+
xtb_api/types/instrument.py,sha256=uxGB3LrE1IgP3UeEMu9c50Mvqmplr3DmgUbLwjg4i14,927
|
|
19
|
+
xtb_api/types/trading.py,sha256=fGLGga-kMX7vDvE848H7lUnw-kHpTcqq6a8P25RDu2k,3033
|
|
20
|
+
xtb_api/types/websocket.py,sha256=66vZSC6hdlglO5EEqPSciBbtBVunGV0L-0pLiZwVrQo,3705
|
|
21
|
+
xtb_api/ws/__init__.py,sha256=6QNzj6rXiGWa9vU-o_IvVTqU7nDqPaYDJnTQhX-1pXY,106
|
|
22
|
+
xtb_api/ws/parsers.py,sha256=ApEjm3uX-QhiyaM8U1RpZByVbU0ijL5jnm4FFIApyNk,6222
|
|
23
|
+
xtb_api/ws/ws_client.py,sha256=X_bBaAw80aHEECRol33aDJqMfVu5onqrQ8a7ANrrZ8s,34077
|
|
24
|
+
xtb_api_python-0.5.2.dist-info/METADATA,sha256=QNHFjD2C2vtf_aqSVn6pT9ikkPhBcfEK9K0pN6Coxpc,8464
|
|
25
|
+
xtb_api_python-0.5.2.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
26
|
+
xtb_api_python-0.5.2.dist-info/entry_points.txt,sha256=HhB6G6gQU-c43Y0YowXSqXXOTCd1CK8fvy5guFdzy0s,50
|
|
27
|
+
xtb_api_python-0.5.2.dist-info/licenses/LICENSE,sha256=fEnrQRlNl8P7GRU9YAaLjbNRfQ0qe0At5LRkCmM4j0I,1073
|
|
28
|
+
xtb_api_python-0.5.2.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Łukasz Lis
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|