flowex 0.1.0__tar.gz
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.
- flowex-0.1.0/LICENSE +21 -0
- flowex-0.1.0/PKG-INFO +199 -0
- flowex-0.1.0/README.md +169 -0
- flowex-0.1.0/flowex/__init__.py +86 -0
- flowex-0.1.0/flowex/_lib.py +67 -0
- flowex-0.1.0/flowex/_models.py +148 -0
- flowex-0.1.0/flowex/lib/libflowex-arm64.so +0 -0
- flowex-0.1.0/flowex/lib/libflowex.dll +0 -0
- flowex-0.1.0/flowex/lib/libflowex.dylib +0 -0
- flowex-0.1.0/flowex/lib/libflowex.so +0 -0
- flowex-0.1.0/flowex.egg-info/PKG-INFO +199 -0
- flowex-0.1.0/flowex.egg-info/SOURCES.txt +14 -0
- flowex-0.1.0/flowex.egg-info/dependency_links.txt +1 -0
- flowex-0.1.0/flowex.egg-info/top_level.txt +1 -0
- flowex-0.1.0/pyproject.toml +56 -0
- flowex-0.1.0/setup.cfg +4 -0
flowex-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 KhavrTrading
|
|
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.
|
flowex-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flowex
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Real-time multi-exchange crypto market data in Python — WebSocket streaming, order book metrics, and per-symbol actor workers for Binance, Bybit, and Bitget.
|
|
5
|
+
Author: KhavrTrading
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/KhavrTrading/flowex-py
|
|
8
|
+
Project-URL: Repository, https://github.com/KhavrTrading/flowex-py
|
|
9
|
+
Project-URL: Issues, https://github.com/KhavrTrading/flowex-py/issues
|
|
10
|
+
Keywords: crypto,trading,market-data,websocket,binance,bybit,bitget,order-book,depth,real-time,go,cgo
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
14
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
23
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
24
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# flowex
|
|
32
|
+
|
|
33
|
+
[](https://github.com/KhavrTrading/flowex-py/actions/workflows/build.yml)
|
|
34
|
+
[](https://pypi.org/project/flowex/)
|
|
35
|
+
[](https://pypi.org/project/flowex/)
|
|
36
|
+
[](LICENSE)
|
|
37
|
+
|
|
38
|
+
Real-time multi-exchange crypto market data for Python — powered by Go via cgo shared library. WebSocket streaming, order book metrics, and per-symbol actor workers for Binance, Bybit, and Bitget.
|
|
39
|
+
|
|
40
|
+
No subprocess, no gRPC, no serialization overhead on the hot path. The Go runtime lives inside the Python process. Every symbol gets its own goroutine. `get_snapshot()` hits the atomic store directly.
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install flowex
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Quick start
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
import time
|
|
52
|
+
from flowex import Manager
|
|
53
|
+
|
|
54
|
+
mgr = Manager("binance")
|
|
55
|
+
mgr.subscribe(["BTCUSDT", "ETHUSDT", "SOLUSDT"])
|
|
56
|
+
time.sleep(2)
|
|
57
|
+
|
|
58
|
+
snap = mgr.get_snapshot("BTCUSDT")
|
|
59
|
+
print(snap.depth.spread_bps)
|
|
60
|
+
print(snap.depth.mid_price)
|
|
61
|
+
print(snap.candles[-1].close)
|
|
62
|
+
|
|
63
|
+
mgr.close()
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Or use as a context manager:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
with Manager("binance") as mgr:
|
|
70
|
+
mgr.subscribe(["BTCUSDT"])
|
|
71
|
+
time.sleep(2)
|
|
72
|
+
snap = mgr.get_snapshot("BTCUSDT")
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Supported exchanges
|
|
76
|
+
|
|
77
|
+
- **Binance** — futures WebSocket (candles, depth, aggTrade)
|
|
78
|
+
- **Bybit** — linear futures WebSocket
|
|
79
|
+
- **Bitget** — USDT futures WebSocket
|
|
80
|
+
|
|
81
|
+
## API
|
|
82
|
+
|
|
83
|
+
### `Manager(exchange)`
|
|
84
|
+
|
|
85
|
+
Create a manager for an exchange. Initializes the Go runtime and WebSocket connections.
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
mgr = Manager("binance") # or "bybit", "bitget"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### `mgr.subscribe(symbols)`
|
|
92
|
+
|
|
93
|
+
Subscribe to one or more symbols. Starts candle, depth, and trade streams for each.
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
mgr.subscribe("BTCUSDT")
|
|
97
|
+
mgr.subscribe(["BTCUSDT", "ETHUSDT", "SOLUSDT"])
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `mgr.get_snapshot(symbol) -> Snapshot | None`
|
|
101
|
+
|
|
102
|
+
Get the latest point-in-time snapshot for a symbol.
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
snap = mgr.get_snapshot("BTCUSDT")
|
|
106
|
+
snap.timestamp # Unix ms
|
|
107
|
+
snap.depth # DepthMetrics
|
|
108
|
+
snap.candles # list[CandleHLCV]
|
|
109
|
+
snap.trades # list[NormalizedTrade]
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `mgr.get_all_snapshots() -> dict[str, Snapshot]`
|
|
113
|
+
|
|
114
|
+
Get snapshots for all subscribed symbols in one call.
|
|
115
|
+
|
|
116
|
+
### `mgr.unsubscribe(symbol)`
|
|
117
|
+
|
|
118
|
+
Remove all streams for a symbol.
|
|
119
|
+
|
|
120
|
+
### `mgr.close()`
|
|
121
|
+
|
|
122
|
+
Shutdown all managers and WebSocket connections.
|
|
123
|
+
|
|
124
|
+
## Data models
|
|
125
|
+
|
|
126
|
+
### `DepthMetrics`
|
|
127
|
+
|
|
128
|
+
Order book metrics computed from raw depth data:
|
|
129
|
+
|
|
130
|
+
| Field | Description |
|
|
131
|
+
|-------|-------------|
|
|
132
|
+
| `mid_price` | (best_bid + best_ask) / 2 |
|
|
133
|
+
| `spread_bps` | Spread in basis points |
|
|
134
|
+
| `bid_liquidity_10` | USD liquidity, top 10 bid levels |
|
|
135
|
+
| `ask_liquidity_10` | USD liquidity, top 10 ask levels |
|
|
136
|
+
| `imbalance_ratio_10` | bid_liq / ask_liq (>1 = bullish) |
|
|
137
|
+
| `slippage_buy_10k` | Estimated slippage % for $10k buy |
|
|
138
|
+
|
|
139
|
+
Plus 70+ more fields: liquidity at 5/10/20/50 levels, volumes, imbalance deltas, largest walls, slippage at 8 USD sizes, velocity, momentum, z-scores, and depth quality metrics.
|
|
140
|
+
|
|
141
|
+
### `CandleHLCV`
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
candle.ts # Unix ms
|
|
145
|
+
candle.open
|
|
146
|
+
candle.high
|
|
147
|
+
candle.low
|
|
148
|
+
candle.close
|
|
149
|
+
candle.volume
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### `NormalizedTrade`
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
trade.timestamp # Unix ms
|
|
156
|
+
trade.price
|
|
157
|
+
trade.size
|
|
158
|
+
trade.side # "buy" or "sell"
|
|
159
|
+
trade.symbol
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Architecture
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
Python process
|
|
166
|
+
|
|
|
167
|
+
+-- ctypes loads libflowex.so <-- Go runtime starts inside Python
|
|
168
|
+
| |
|
|
169
|
+
| +-- Manager (binance)
|
|
170
|
+
| | +-- Worker: BTCUSDT -> atomic snapshot
|
|
171
|
+
| | +-- Worker: ETHUSDT -> atomic snapshot
|
|
172
|
+
| | +-- Worker: SOLUSDT -> atomic snapshot
|
|
173
|
+
| |
|
|
174
|
+
| +-- Manager (bybit)
|
|
175
|
+
| +-- Worker: BTCUSDT -> atomic snapshot
|
|
176
|
+
|
|
|
177
|
+
+-- mgr.subscribe(["BTCUSDT"]) -> FlowexSubscribeBatch()
|
|
178
|
+
+-- mgr.get_snapshot("BTCUSDT") -> FlowexGetSnapshot() -> atomic.Load -> JSON -> Python
|
|
179
|
+
+-- mgr.get_all_snapshots() -> FlowexGetSnapshots() -> one call, all symbols
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Build from source
|
|
183
|
+
|
|
184
|
+
Requires Go 1.22+ and Python 3.10+.
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# macOS (Apple Silicon)
|
|
188
|
+
make build-mac
|
|
189
|
+
|
|
190
|
+
# Linux (amd64)
|
|
191
|
+
make build-linux
|
|
192
|
+
|
|
193
|
+
# All platforms (requires cross-compilers)
|
|
194
|
+
make build-all
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## License
|
|
198
|
+
|
|
199
|
+
MIT
|
flowex-0.1.0/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# flowex
|
|
2
|
+
|
|
3
|
+
[](https://github.com/KhavrTrading/flowex-py/actions/workflows/build.yml)
|
|
4
|
+
[](https://pypi.org/project/flowex/)
|
|
5
|
+
[](https://pypi.org/project/flowex/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
Real-time multi-exchange crypto market data for Python — powered by Go via cgo shared library. WebSocket streaming, order book metrics, and per-symbol actor workers for Binance, Bybit, and Bitget.
|
|
9
|
+
|
|
10
|
+
No subprocess, no gRPC, no serialization overhead on the hot path. The Go runtime lives inside the Python process. Every symbol gets its own goroutine. `get_snapshot()` hits the atomic store directly.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install flowex
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick start
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
import time
|
|
22
|
+
from flowex import Manager
|
|
23
|
+
|
|
24
|
+
mgr = Manager("binance")
|
|
25
|
+
mgr.subscribe(["BTCUSDT", "ETHUSDT", "SOLUSDT"])
|
|
26
|
+
time.sleep(2)
|
|
27
|
+
|
|
28
|
+
snap = mgr.get_snapshot("BTCUSDT")
|
|
29
|
+
print(snap.depth.spread_bps)
|
|
30
|
+
print(snap.depth.mid_price)
|
|
31
|
+
print(snap.candles[-1].close)
|
|
32
|
+
|
|
33
|
+
mgr.close()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or use as a context manager:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
with Manager("binance") as mgr:
|
|
40
|
+
mgr.subscribe(["BTCUSDT"])
|
|
41
|
+
time.sleep(2)
|
|
42
|
+
snap = mgr.get_snapshot("BTCUSDT")
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Supported exchanges
|
|
46
|
+
|
|
47
|
+
- **Binance** — futures WebSocket (candles, depth, aggTrade)
|
|
48
|
+
- **Bybit** — linear futures WebSocket
|
|
49
|
+
- **Bitget** — USDT futures WebSocket
|
|
50
|
+
|
|
51
|
+
## API
|
|
52
|
+
|
|
53
|
+
### `Manager(exchange)`
|
|
54
|
+
|
|
55
|
+
Create a manager for an exchange. Initializes the Go runtime and WebSocket connections.
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
mgr = Manager("binance") # or "bybit", "bitget"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### `mgr.subscribe(symbols)`
|
|
62
|
+
|
|
63
|
+
Subscribe to one or more symbols. Starts candle, depth, and trade streams for each.
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
mgr.subscribe("BTCUSDT")
|
|
67
|
+
mgr.subscribe(["BTCUSDT", "ETHUSDT", "SOLUSDT"])
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### `mgr.get_snapshot(symbol) -> Snapshot | None`
|
|
71
|
+
|
|
72
|
+
Get the latest point-in-time snapshot for a symbol.
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
snap = mgr.get_snapshot("BTCUSDT")
|
|
76
|
+
snap.timestamp # Unix ms
|
|
77
|
+
snap.depth # DepthMetrics
|
|
78
|
+
snap.candles # list[CandleHLCV]
|
|
79
|
+
snap.trades # list[NormalizedTrade]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### `mgr.get_all_snapshots() -> dict[str, Snapshot]`
|
|
83
|
+
|
|
84
|
+
Get snapshots for all subscribed symbols in one call.
|
|
85
|
+
|
|
86
|
+
### `mgr.unsubscribe(symbol)`
|
|
87
|
+
|
|
88
|
+
Remove all streams for a symbol.
|
|
89
|
+
|
|
90
|
+
### `mgr.close()`
|
|
91
|
+
|
|
92
|
+
Shutdown all managers and WebSocket connections.
|
|
93
|
+
|
|
94
|
+
## Data models
|
|
95
|
+
|
|
96
|
+
### `DepthMetrics`
|
|
97
|
+
|
|
98
|
+
Order book metrics computed from raw depth data:
|
|
99
|
+
|
|
100
|
+
| Field | Description |
|
|
101
|
+
|-------|-------------|
|
|
102
|
+
| `mid_price` | (best_bid + best_ask) / 2 |
|
|
103
|
+
| `spread_bps` | Spread in basis points |
|
|
104
|
+
| `bid_liquidity_10` | USD liquidity, top 10 bid levels |
|
|
105
|
+
| `ask_liquidity_10` | USD liquidity, top 10 ask levels |
|
|
106
|
+
| `imbalance_ratio_10` | bid_liq / ask_liq (>1 = bullish) |
|
|
107
|
+
| `slippage_buy_10k` | Estimated slippage % for $10k buy |
|
|
108
|
+
|
|
109
|
+
Plus 70+ more fields: liquidity at 5/10/20/50 levels, volumes, imbalance deltas, largest walls, slippage at 8 USD sizes, velocity, momentum, z-scores, and depth quality metrics.
|
|
110
|
+
|
|
111
|
+
### `CandleHLCV`
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
candle.ts # Unix ms
|
|
115
|
+
candle.open
|
|
116
|
+
candle.high
|
|
117
|
+
candle.low
|
|
118
|
+
candle.close
|
|
119
|
+
candle.volume
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### `NormalizedTrade`
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
trade.timestamp # Unix ms
|
|
126
|
+
trade.price
|
|
127
|
+
trade.size
|
|
128
|
+
trade.side # "buy" or "sell"
|
|
129
|
+
trade.symbol
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Architecture
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
Python process
|
|
136
|
+
|
|
|
137
|
+
+-- ctypes loads libflowex.so <-- Go runtime starts inside Python
|
|
138
|
+
| |
|
|
139
|
+
| +-- Manager (binance)
|
|
140
|
+
| | +-- Worker: BTCUSDT -> atomic snapshot
|
|
141
|
+
| | +-- Worker: ETHUSDT -> atomic snapshot
|
|
142
|
+
| | +-- Worker: SOLUSDT -> atomic snapshot
|
|
143
|
+
| |
|
|
144
|
+
| +-- Manager (bybit)
|
|
145
|
+
| +-- Worker: BTCUSDT -> atomic snapshot
|
|
146
|
+
|
|
|
147
|
+
+-- mgr.subscribe(["BTCUSDT"]) -> FlowexSubscribeBatch()
|
|
148
|
+
+-- mgr.get_snapshot("BTCUSDT") -> FlowexGetSnapshot() -> atomic.Load -> JSON -> Python
|
|
149
|
+
+-- mgr.get_all_snapshots() -> FlowexGetSnapshots() -> one call, all symbols
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Build from source
|
|
153
|
+
|
|
154
|
+
Requires Go 1.22+ and Python 3.10+.
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# macOS (Apple Silicon)
|
|
158
|
+
make build-mac
|
|
159
|
+
|
|
160
|
+
# Linux (amd64)
|
|
161
|
+
make build-linux
|
|
162
|
+
|
|
163
|
+
# All platforms (requires cross-compilers)
|
|
164
|
+
make build-all
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import atexit
|
|
4
|
+
import ctypes
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
from flowex._lib import lib as _lib
|
|
8
|
+
from flowex._models import CandleHLCV, DepthMetrics, NormalizedTrade, Snapshot
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"Manager",
|
|
12
|
+
"Snapshot",
|
|
13
|
+
"CandleHLCV",
|
|
14
|
+
"DepthMetrics",
|
|
15
|
+
"NormalizedTrade",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
_shutdown_registered = False
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Manager:
|
|
22
|
+
"""Wraps a flowex exchange manager loaded via the shared library.
|
|
23
|
+
|
|
24
|
+
Usage::
|
|
25
|
+
|
|
26
|
+
with Manager("binance") as mgr:
|
|
27
|
+
mgr.subscribe(["BTCUSDT", "ETHUSDT"])
|
|
28
|
+
snap = mgr.get_snapshot("BTCUSDT")
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, exchange: str) -> None:
|
|
32
|
+
global _shutdown_registered
|
|
33
|
+
self._exchange = exchange.lower()
|
|
34
|
+
self._exchange_b = self._exchange.encode("utf-8")
|
|
35
|
+
rc = _lib.FlowexInit(self._exchange_b)
|
|
36
|
+
if rc != 0:
|
|
37
|
+
raise RuntimeError(f"FlowexInit failed for {exchange!r}")
|
|
38
|
+
if not _shutdown_registered:
|
|
39
|
+
atexit.register(_lib.FlowexShutdown)
|
|
40
|
+
_shutdown_registered = True
|
|
41
|
+
|
|
42
|
+
def subscribe(self, symbols: list[str] | str) -> None:
|
|
43
|
+
if isinstance(symbols, str):
|
|
44
|
+
symbols = [symbols]
|
|
45
|
+
arr = (ctypes.c_char_p * len(symbols))(
|
|
46
|
+
*(s.encode("utf-8") for s in symbols)
|
|
47
|
+
)
|
|
48
|
+
rc = _lib.FlowexSubscribeBatch(self._exchange_b, arr, len(symbols))
|
|
49
|
+
if rc != 0:
|
|
50
|
+
raise RuntimeError("FlowexSubscribeBatch failed")
|
|
51
|
+
|
|
52
|
+
def get_snapshot(self, symbol: str) -> Snapshot | None:
|
|
53
|
+
ptr = _lib.FlowexGetSnapshot(self._exchange_b, symbol.encode("utf-8"))
|
|
54
|
+
if not ptr:
|
|
55
|
+
return None
|
|
56
|
+
try:
|
|
57
|
+
raw = ctypes.string_at(ptr)
|
|
58
|
+
data = json.loads(raw)
|
|
59
|
+
finally:
|
|
60
|
+
_lib.FlowexFree(ptr)
|
|
61
|
+
return Snapshot.from_dict(data)
|
|
62
|
+
|
|
63
|
+
def get_all_snapshots(self) -> dict[str, Snapshot]:
|
|
64
|
+
ptr = _lib.FlowexGetSnapshots(self._exchange_b)
|
|
65
|
+
if not ptr:
|
|
66
|
+
return {}
|
|
67
|
+
try:
|
|
68
|
+
raw = ctypes.string_at(ptr)
|
|
69
|
+
data = json.loads(raw)
|
|
70
|
+
finally:
|
|
71
|
+
_lib.FlowexFree(ptr)
|
|
72
|
+
return {sym: Snapshot.from_dict(snap) for sym, snap in data.items()}
|
|
73
|
+
|
|
74
|
+
def unsubscribe(self, symbol: str) -> None:
|
|
75
|
+
rc = _lib.FlowexUnsubscribe(self._exchange_b, symbol.encode("utf-8"))
|
|
76
|
+
if rc != 0:
|
|
77
|
+
raise RuntimeError(f"FlowexUnsubscribe failed for {symbol!r}")
|
|
78
|
+
|
|
79
|
+
def close(self) -> None:
|
|
80
|
+
_lib.FlowexShutdown()
|
|
81
|
+
|
|
82
|
+
def __enter__(self) -> Manager:
|
|
83
|
+
return self
|
|
84
|
+
|
|
85
|
+
def __exit__(self, *args: object) -> None:
|
|
86
|
+
self.close()
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import ctypes
|
|
2
|
+
import os
|
|
3
|
+
import platform
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _load():
|
|
7
|
+
system = platform.system()
|
|
8
|
+
machine = platform.machine()
|
|
9
|
+
|
|
10
|
+
pkg_dir = os.path.dirname(os.path.abspath(__file__))
|
|
11
|
+
lib_dir = os.path.join(pkg_dir, "lib")
|
|
12
|
+
|
|
13
|
+
if system == "Linux":
|
|
14
|
+
if machine in ("aarch64", "arm64"):
|
|
15
|
+
name = "libflowex-arm64.so"
|
|
16
|
+
else:
|
|
17
|
+
name = "libflowex.so"
|
|
18
|
+
elif system == "Darwin":
|
|
19
|
+
name = "libflowex.dylib"
|
|
20
|
+
elif system == "Windows":
|
|
21
|
+
name = "libflowex.dll"
|
|
22
|
+
else:
|
|
23
|
+
raise OSError(f"Unsupported platform: {system}")
|
|
24
|
+
|
|
25
|
+
path = os.path.join(lib_dir, name)
|
|
26
|
+
lib = ctypes.CDLL(path)
|
|
27
|
+
|
|
28
|
+
# FlowexInit(exchange *char) -> int
|
|
29
|
+
lib.FlowexInit.argtypes = [ctypes.c_char_p]
|
|
30
|
+
lib.FlowexInit.restype = ctypes.c_int
|
|
31
|
+
|
|
32
|
+
# FlowexSubscribe(exchange *char, symbol *char) -> int
|
|
33
|
+
lib.FlowexSubscribe.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
|
|
34
|
+
lib.FlowexSubscribe.restype = ctypes.c_int
|
|
35
|
+
|
|
36
|
+
# FlowexSubscribeBatch(exchange *char, symbols **char, count int) -> int
|
|
37
|
+
lib.FlowexSubscribeBatch.argtypes = [
|
|
38
|
+
ctypes.c_char_p,
|
|
39
|
+
ctypes.POINTER(ctypes.c_char_p),
|
|
40
|
+
ctypes.c_int,
|
|
41
|
+
]
|
|
42
|
+
lib.FlowexSubscribeBatch.restype = ctypes.c_int
|
|
43
|
+
|
|
44
|
+
# FlowexGetSnapshot(exchange *char, symbol *char) -> *char (caller must free)
|
|
45
|
+
lib.FlowexGetSnapshot.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
|
|
46
|
+
lib.FlowexGetSnapshot.restype = ctypes.c_void_p
|
|
47
|
+
|
|
48
|
+
# FlowexGetSnapshots(exchange *char) -> *char (caller must free)
|
|
49
|
+
lib.FlowexGetSnapshots.argtypes = [ctypes.c_char_p]
|
|
50
|
+
lib.FlowexGetSnapshots.restype = ctypes.c_void_p
|
|
51
|
+
|
|
52
|
+
# FlowexUnsubscribe(exchange *char, symbol *char) -> int
|
|
53
|
+
lib.FlowexUnsubscribe.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
|
|
54
|
+
lib.FlowexUnsubscribe.restype = ctypes.c_int
|
|
55
|
+
|
|
56
|
+
# FlowexShutdown() -> void
|
|
57
|
+
lib.FlowexShutdown.argtypes = []
|
|
58
|
+
lib.FlowexShutdown.restype = None
|
|
59
|
+
|
|
60
|
+
# FlowexFree(ptr *char) -> void
|
|
61
|
+
lib.FlowexFree.argtypes = [ctypes.c_void_p]
|
|
62
|
+
lib.FlowexFree.restype = None
|
|
63
|
+
|
|
64
|
+
return lib
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
lib = _load()
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class CandleHLCV:
|
|
9
|
+
ts: int = 0
|
|
10
|
+
open: float = 0.0
|
|
11
|
+
high: float = 0.0
|
|
12
|
+
low: float = 0.0
|
|
13
|
+
close: float = 0.0
|
|
14
|
+
volume: float = 0.0
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class NormalizedTrade:
|
|
19
|
+
timestamp: int = 0
|
|
20
|
+
price: float = 0.0
|
|
21
|
+
size: float = 0.0
|
|
22
|
+
size_usd: float = 0.0
|
|
23
|
+
side: str = ""
|
|
24
|
+
trade_id: str = ""
|
|
25
|
+
symbol: str = ""
|
|
26
|
+
exchange: str = ""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class DepthMetrics:
|
|
31
|
+
# Basic
|
|
32
|
+
timestamp: int = 0
|
|
33
|
+
symbol: str = ""
|
|
34
|
+
best_bid: float = 0.0
|
|
35
|
+
best_ask: float = 0.0
|
|
36
|
+
spread: float = 0.0
|
|
37
|
+
spread_bps: float = 0.0
|
|
38
|
+
mid_price: float = 0.0
|
|
39
|
+
|
|
40
|
+
# Liquidity (USD) at different depths
|
|
41
|
+
bid_liquidity_5: float = 0.0
|
|
42
|
+
ask_liquidity_5: float = 0.0
|
|
43
|
+
bid_liquidity_10: float = 0.0
|
|
44
|
+
ask_liquidity_10: float = 0.0
|
|
45
|
+
bid_liquidity_20: float = 0.0
|
|
46
|
+
ask_liquidity_20: float = 0.0
|
|
47
|
+
bid_liquidity_50: float = 0.0
|
|
48
|
+
ask_liquidity_50: float = 0.0
|
|
49
|
+
|
|
50
|
+
# Volumes (coin size) at different depths
|
|
51
|
+
bid_volume_5: float = 0.0
|
|
52
|
+
ask_volume_5: float = 0.0
|
|
53
|
+
bid_volume_10: float = 0.0
|
|
54
|
+
ask_volume_10: float = 0.0
|
|
55
|
+
bid_volume_20: float = 0.0
|
|
56
|
+
ask_volume_20: float = 0.0
|
|
57
|
+
bid_volume_50: float = 0.0
|
|
58
|
+
ask_volume_50: float = 0.0
|
|
59
|
+
|
|
60
|
+
# Imbalance ratios
|
|
61
|
+
imbalance_ratio_5: float = 0.0
|
|
62
|
+
imbalance_ratio_10: float = 0.0
|
|
63
|
+
imbalance_ratio_20: float = 0.0
|
|
64
|
+
imbalance_ratio_50: float = 0.0
|
|
65
|
+
|
|
66
|
+
# Imbalance deltas
|
|
67
|
+
imbalance_delta_10: float = 0.0
|
|
68
|
+
imbalance_delta_20: float = 0.0
|
|
69
|
+
|
|
70
|
+
# Largest single orders (walls)
|
|
71
|
+
largest_bid_size: float = 0.0
|
|
72
|
+
largest_bid_price: float = 0.0
|
|
73
|
+
largest_bid_value: float = 0.0
|
|
74
|
+
largest_ask_size: float = 0.0
|
|
75
|
+
largest_ask_price: float = 0.0
|
|
76
|
+
largest_ask_value: float = 0.0
|
|
77
|
+
|
|
78
|
+
# Slippage estimation (%)
|
|
79
|
+
slippage_buy_100: float = 0.0
|
|
80
|
+
slippage_sell_100: float = 0.0
|
|
81
|
+
slippage_buy_1k: float = 0.0
|
|
82
|
+
slippage_sell_1k: float = 0.0
|
|
83
|
+
slippage_buy_5k: float = 0.0
|
|
84
|
+
slippage_sell_5k: float = 0.0
|
|
85
|
+
slippage_buy_10k: float = 0.0
|
|
86
|
+
slippage_sell_10k: float = 0.0
|
|
87
|
+
slippage_buy_50k: float = 0.0
|
|
88
|
+
slippage_sell_50k: float = 0.0
|
|
89
|
+
slippage_buy_100k: float = 0.0
|
|
90
|
+
slippage_sell_100k: float = 0.0
|
|
91
|
+
slippage_buy_500k: float = 0.0
|
|
92
|
+
slippage_sell_500k: float = 0.0
|
|
93
|
+
slippage_buy_1m: float = 0.0
|
|
94
|
+
slippage_sell_1m: float = 0.0
|
|
95
|
+
|
|
96
|
+
# Velocity metrics
|
|
97
|
+
liquidity_velocity_10: float = 0.0
|
|
98
|
+
liquidity_velocity_50: float = 0.0
|
|
99
|
+
imbalance_velocity: float = 0.0
|
|
100
|
+
spread_velocity: float = 0.0
|
|
101
|
+
wall_velocity: float = 0.0
|
|
102
|
+
|
|
103
|
+
# Momentum
|
|
104
|
+
buy_pressure_momentum: float = 0.0
|
|
105
|
+
sell_pressure_momentum: float = 0.0
|
|
106
|
+
wall_building_bid: bool = False
|
|
107
|
+
wall_building_ask: bool = False
|
|
108
|
+
|
|
109
|
+
# Z-scores
|
|
110
|
+
liquidity_zscore_10: float = 0.0
|
|
111
|
+
imbalance_zscore: float = 0.0
|
|
112
|
+
spread_zscore: float = 0.0
|
|
113
|
+
|
|
114
|
+
# Depth quality
|
|
115
|
+
bid_levels_count: int = 0
|
|
116
|
+
ask_levels_count: int = 0
|
|
117
|
+
avg_bid_size_10: float = 0.0
|
|
118
|
+
avg_ask_size_10: float = 0.0
|
|
119
|
+
top_bid_concentration_5: float = 0.0
|
|
120
|
+
top_ask_concentration_5: float = 0.0
|
|
121
|
+
spread_norm_imbalance_delta_10: float = 0.0
|
|
122
|
+
spread_norm_imbalance_delta_20: float = 0.0
|
|
123
|
+
slippage_gradient_buy: float = 0.0
|
|
124
|
+
slippage_gradient_sell: float = 0.0
|
|
125
|
+
slippage_skew_1k: float = 0.0
|
|
126
|
+
slippage_skew_10k: float = 0.0
|
|
127
|
+
|
|
128
|
+
@classmethod
|
|
129
|
+
def from_dict(cls, d: dict) -> DepthMetrics:
|
|
130
|
+
known = {f.name for f in dataclasses.fields(cls)}
|
|
131
|
+
return cls(**{k: v for k, v in d.items() if k in known})
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@dataclass
|
|
135
|
+
class Snapshot:
|
|
136
|
+
timestamp: int = 0
|
|
137
|
+
candles: list[CandleHLCV] = field(default_factory=list)
|
|
138
|
+
depth: DepthMetrics | None = None
|
|
139
|
+
trades: list[NormalizedTrade] = field(default_factory=list)
|
|
140
|
+
|
|
141
|
+
@classmethod
|
|
142
|
+
def from_dict(cls, d: dict) -> Snapshot:
|
|
143
|
+
return cls(
|
|
144
|
+
timestamp=d.get("timestamp", 0),
|
|
145
|
+
candles=[CandleHLCV(**c) for c in d.get("candles") or []],
|
|
146
|
+
depth=DepthMetrics.from_dict(d["depth"]) if d.get("depth") else None,
|
|
147
|
+
trades=[NormalizedTrade(**t) for t in d.get("trades") or []],
|
|
148
|
+
)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flowex
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Real-time multi-exchange crypto market data in Python — WebSocket streaming, order book metrics, and per-symbol actor workers for Binance, Bybit, and Bitget.
|
|
5
|
+
Author: KhavrTrading
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/KhavrTrading/flowex-py
|
|
8
|
+
Project-URL: Repository, https://github.com/KhavrTrading/flowex-py
|
|
9
|
+
Project-URL: Issues, https://github.com/KhavrTrading/flowex-py/issues
|
|
10
|
+
Keywords: crypto,trading,market-data,websocket,binance,bybit,bitget,order-book,depth,real-time,go,cgo
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
14
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
23
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
24
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# flowex
|
|
32
|
+
|
|
33
|
+
[](https://github.com/KhavrTrading/flowex-py/actions/workflows/build.yml)
|
|
34
|
+
[](https://pypi.org/project/flowex/)
|
|
35
|
+
[](https://pypi.org/project/flowex/)
|
|
36
|
+
[](LICENSE)
|
|
37
|
+
|
|
38
|
+
Real-time multi-exchange crypto market data for Python — powered by Go via cgo shared library. WebSocket streaming, order book metrics, and per-symbol actor workers for Binance, Bybit, and Bitget.
|
|
39
|
+
|
|
40
|
+
No subprocess, no gRPC, no serialization overhead on the hot path. The Go runtime lives inside the Python process. Every symbol gets its own goroutine. `get_snapshot()` hits the atomic store directly.
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install flowex
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Quick start
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
import time
|
|
52
|
+
from flowex import Manager
|
|
53
|
+
|
|
54
|
+
mgr = Manager("binance")
|
|
55
|
+
mgr.subscribe(["BTCUSDT", "ETHUSDT", "SOLUSDT"])
|
|
56
|
+
time.sleep(2)
|
|
57
|
+
|
|
58
|
+
snap = mgr.get_snapshot("BTCUSDT")
|
|
59
|
+
print(snap.depth.spread_bps)
|
|
60
|
+
print(snap.depth.mid_price)
|
|
61
|
+
print(snap.candles[-1].close)
|
|
62
|
+
|
|
63
|
+
mgr.close()
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Or use as a context manager:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
with Manager("binance") as mgr:
|
|
70
|
+
mgr.subscribe(["BTCUSDT"])
|
|
71
|
+
time.sleep(2)
|
|
72
|
+
snap = mgr.get_snapshot("BTCUSDT")
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Supported exchanges
|
|
76
|
+
|
|
77
|
+
- **Binance** — futures WebSocket (candles, depth, aggTrade)
|
|
78
|
+
- **Bybit** — linear futures WebSocket
|
|
79
|
+
- **Bitget** — USDT futures WebSocket
|
|
80
|
+
|
|
81
|
+
## API
|
|
82
|
+
|
|
83
|
+
### `Manager(exchange)`
|
|
84
|
+
|
|
85
|
+
Create a manager for an exchange. Initializes the Go runtime and WebSocket connections.
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
mgr = Manager("binance") # or "bybit", "bitget"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### `mgr.subscribe(symbols)`
|
|
92
|
+
|
|
93
|
+
Subscribe to one or more symbols. Starts candle, depth, and trade streams for each.
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
mgr.subscribe("BTCUSDT")
|
|
97
|
+
mgr.subscribe(["BTCUSDT", "ETHUSDT", "SOLUSDT"])
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `mgr.get_snapshot(symbol) -> Snapshot | None`
|
|
101
|
+
|
|
102
|
+
Get the latest point-in-time snapshot for a symbol.
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
snap = mgr.get_snapshot("BTCUSDT")
|
|
106
|
+
snap.timestamp # Unix ms
|
|
107
|
+
snap.depth # DepthMetrics
|
|
108
|
+
snap.candles # list[CandleHLCV]
|
|
109
|
+
snap.trades # list[NormalizedTrade]
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `mgr.get_all_snapshots() -> dict[str, Snapshot]`
|
|
113
|
+
|
|
114
|
+
Get snapshots for all subscribed symbols in one call.
|
|
115
|
+
|
|
116
|
+
### `mgr.unsubscribe(symbol)`
|
|
117
|
+
|
|
118
|
+
Remove all streams for a symbol.
|
|
119
|
+
|
|
120
|
+
### `mgr.close()`
|
|
121
|
+
|
|
122
|
+
Shutdown all managers and WebSocket connections.
|
|
123
|
+
|
|
124
|
+
## Data models
|
|
125
|
+
|
|
126
|
+
### `DepthMetrics`
|
|
127
|
+
|
|
128
|
+
Order book metrics computed from raw depth data:
|
|
129
|
+
|
|
130
|
+
| Field | Description |
|
|
131
|
+
|-------|-------------|
|
|
132
|
+
| `mid_price` | (best_bid + best_ask) / 2 |
|
|
133
|
+
| `spread_bps` | Spread in basis points |
|
|
134
|
+
| `bid_liquidity_10` | USD liquidity, top 10 bid levels |
|
|
135
|
+
| `ask_liquidity_10` | USD liquidity, top 10 ask levels |
|
|
136
|
+
| `imbalance_ratio_10` | bid_liq / ask_liq (>1 = bullish) |
|
|
137
|
+
| `slippage_buy_10k` | Estimated slippage % for $10k buy |
|
|
138
|
+
|
|
139
|
+
Plus 70+ more fields: liquidity at 5/10/20/50 levels, volumes, imbalance deltas, largest walls, slippage at 8 USD sizes, velocity, momentum, z-scores, and depth quality metrics.
|
|
140
|
+
|
|
141
|
+
### `CandleHLCV`
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
candle.ts # Unix ms
|
|
145
|
+
candle.open
|
|
146
|
+
candle.high
|
|
147
|
+
candle.low
|
|
148
|
+
candle.close
|
|
149
|
+
candle.volume
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### `NormalizedTrade`
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
trade.timestamp # Unix ms
|
|
156
|
+
trade.price
|
|
157
|
+
trade.size
|
|
158
|
+
trade.side # "buy" or "sell"
|
|
159
|
+
trade.symbol
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Architecture
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
Python process
|
|
166
|
+
|
|
|
167
|
+
+-- ctypes loads libflowex.so <-- Go runtime starts inside Python
|
|
168
|
+
| |
|
|
169
|
+
| +-- Manager (binance)
|
|
170
|
+
| | +-- Worker: BTCUSDT -> atomic snapshot
|
|
171
|
+
| | +-- Worker: ETHUSDT -> atomic snapshot
|
|
172
|
+
| | +-- Worker: SOLUSDT -> atomic snapshot
|
|
173
|
+
| |
|
|
174
|
+
| +-- Manager (bybit)
|
|
175
|
+
| +-- Worker: BTCUSDT -> atomic snapshot
|
|
176
|
+
|
|
|
177
|
+
+-- mgr.subscribe(["BTCUSDT"]) -> FlowexSubscribeBatch()
|
|
178
|
+
+-- mgr.get_snapshot("BTCUSDT") -> FlowexGetSnapshot() -> atomic.Load -> JSON -> Python
|
|
179
|
+
+-- mgr.get_all_snapshots() -> FlowexGetSnapshots() -> one call, all symbols
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Build from source
|
|
183
|
+
|
|
184
|
+
Requires Go 1.22+ and Python 3.10+.
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# macOS (Apple Silicon)
|
|
188
|
+
make build-mac
|
|
189
|
+
|
|
190
|
+
# Linux (amd64)
|
|
191
|
+
make build-linux
|
|
192
|
+
|
|
193
|
+
# All platforms (requires cross-compilers)
|
|
194
|
+
make build-all
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## License
|
|
198
|
+
|
|
199
|
+
MIT
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
flowex/__init__.py
|
|
5
|
+
flowex/_lib.py
|
|
6
|
+
flowex/_models.py
|
|
7
|
+
flowex.egg-info/PKG-INFO
|
|
8
|
+
flowex.egg-info/SOURCES.txt
|
|
9
|
+
flowex.egg-info/dependency_links.txt
|
|
10
|
+
flowex.egg-info/top_level.txt
|
|
11
|
+
flowex/lib/libflowex-arm64.so
|
|
12
|
+
flowex/lib/libflowex.dll
|
|
13
|
+
flowex/lib/libflowex.dylib
|
|
14
|
+
flowex/lib/libflowex.so
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
flowex
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "flowex"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Real-time multi-exchange crypto market data in Python — WebSocket streaming, order book metrics, and per-symbol actor workers for Binance, Bybit, and Bitget."
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "KhavrTrading" },
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"crypto",
|
|
17
|
+
"trading",
|
|
18
|
+
"market-data",
|
|
19
|
+
"websocket",
|
|
20
|
+
"binance",
|
|
21
|
+
"bybit",
|
|
22
|
+
"bitget",
|
|
23
|
+
"order-book",
|
|
24
|
+
"depth",
|
|
25
|
+
"real-time",
|
|
26
|
+
"go",
|
|
27
|
+
"cgo",
|
|
28
|
+
]
|
|
29
|
+
classifiers = [
|
|
30
|
+
"Development Status :: 4 - Beta",
|
|
31
|
+
"Intended Audience :: Developers",
|
|
32
|
+
"Intended Audience :: Financial and Insurance Industry",
|
|
33
|
+
"Operating System :: POSIX :: Linux",
|
|
34
|
+
"Operating System :: MacOS",
|
|
35
|
+
"Operating System :: Microsoft :: Windows",
|
|
36
|
+
"Programming Language :: Python :: 3",
|
|
37
|
+
"Programming Language :: Python :: 3.10",
|
|
38
|
+
"Programming Language :: Python :: 3.11",
|
|
39
|
+
"Programming Language :: Python :: 3.12",
|
|
40
|
+
"Programming Language :: Python :: 3.13",
|
|
41
|
+
"Topic :: Office/Business :: Financial",
|
|
42
|
+
"Topic :: Office/Business :: Financial :: Investment",
|
|
43
|
+
"Topic :: Software Development :: Libraries",
|
|
44
|
+
"Typing :: Typed",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[project.urls]
|
|
48
|
+
Homepage = "https://github.com/KhavrTrading/flowex-py"
|
|
49
|
+
Repository = "https://github.com/KhavrTrading/flowex-py"
|
|
50
|
+
Issues = "https://github.com/KhavrTrading/flowex-py/issues"
|
|
51
|
+
|
|
52
|
+
[tool.setuptools.packages.find]
|
|
53
|
+
include = ["flowex*"]
|
|
54
|
+
|
|
55
|
+
[tool.setuptools.package-data]
|
|
56
|
+
flowex = ["lib/*"]
|
flowex-0.1.0/setup.cfg
ADDED