blockfill 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.
@@ -0,0 +1,299 @@
1
+ Metadata-Version: 2.4
2
+ Name: blockfill
3
+ Version: 0.1.0
4
+ Summary: Python SDK for the blockfill execution daemon
5
+ Author-email: Mavri-X <robot@mavri-x.ai>
6
+ License: Proprietary
7
+ Project-URL: Homepage, https://github.com/mavri-x/blockfill
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: toml
11
+
12
+ # blockfill Python SDK
13
+
14
+ Python wrapper for the [blockfill](../executor/) execution daemon. Covers the full lifecycle: install binary, configure credentials, manage daemon, place/query/cancel tickets.
15
+
16
+ ## Requirements
17
+
18
+ - Python 3.10+
19
+ - blockfill binary (see [Install](#install))
20
+ - blockfill daemon running (see [Daemon](#daemon))
21
+
22
+ ## Install
23
+
24
+ ```bash
25
+ pip install blockfill
26
+ # or from source
27
+ pip install -e /path/to/python-sdk
28
+ ```
29
+
30
+ ## Quickstart
31
+
32
+ ```python
33
+ from blockfill import Blockfill
34
+
35
+ bf = Blockfill(
36
+ binary_path="/path/to/blockfill", # or ~/.blockfill/bin/blockfill
37
+ data_dir="~/.blockfill",
38
+ )
39
+
40
+ # First-time setup
41
+ bf.set_credentials("binance-futures", api_key="...", api_secret="...")
42
+ bf.set_qtex_endpoint("https://qtex.example.com")
43
+
44
+ # Start daemon
45
+ bf.start(env={"BLOCKFILL_API_KEY": "..."})
46
+ bf.health()
47
+
48
+ # Place a ticket
49
+ ticket = bf.place(
50
+ exchange="binance-futures",
51
+ symbol="btcusdt",
52
+ strategy="maker_l2",
53
+ target_position=0.1,
54
+ time_constraint_ms=300_000,
55
+ )
56
+ print(ticket.ticket_id, ticket.status) # tkt_xxx NEW
57
+
58
+ # Query
59
+ tickets = bf.query(status="NEW")
60
+
61
+ # Cancel
62
+ bf.cancel(ticket.ticket_id)
63
+
64
+ # Stop daemon
65
+ bf.stop()
66
+ ```
67
+
68
+ ---
69
+
70
+ ## API Reference
71
+
72
+ ### `Blockfill(binary_path, data_dir, timeout_s)`
73
+
74
+ | Parameter | Default | Description |
75
+ | ------------- | ---------------------------- | ------------------------------------- |
76
+ | `binary_path` | `~/.blockfill/bin/blockfill` | Path to blockfill binary |
77
+ | `data_dir` | `~/.blockfill` | Data directory (config, socket, logs) |
78
+ | `timeout_s` | `10.0` | RPC call timeout (seconds) |
79
+
80
+ ---
81
+
82
+ ### Install & Version
83
+
84
+ ```python
85
+ bf.install(version="latest", force=False) -> str
86
+ # Returns installed version string.
87
+ # If binary already exists and force=False, skips download and returns current version.
88
+
89
+ bf.version() -> str
90
+ # Returns "blockfill 0.1.0"
91
+ ```
92
+
93
+ ---
94
+
95
+ ### Credentials
96
+
97
+ ```python
98
+ bf.set_credentials(
99
+ exchange: str, # "binance-futures" | "okx-swap"
100
+ api_key: str,
101
+ api_secret: str,
102
+ api_passphrase: str | None = None, # OKX only
103
+ ) -> None
104
+ # Writes to {data_dir}/config.toml (chmod 0600)
105
+
106
+ bf.set_qtex_endpoint(endpoint: str) -> None
107
+ # e.g. bf.set_qtex_endpoint("https://qtex.example.com")
108
+ ```
109
+
110
+ ---
111
+
112
+ ### Daemon
113
+
114
+ ```python
115
+ bf.start(wait_timeout_s=10.0, env=None) -> None
116
+ # Starts daemon in background. No-op if already running.
117
+ # env: extra environment variables (e.g. {"BLOCKFILL_API_KEY": "..."})
118
+
119
+ bf.stop(wait_timeout_s=5.0) -> None
120
+ # Graceful shutdown. No-op if not running.
121
+
122
+ bf.restart() -> None
123
+
124
+ bf.is_running() -> bool
125
+
126
+ bf.health() -> DaemonStatus
127
+ # Raises DaemonNotRunning if daemon is not up.
128
+
129
+ bf.run_foreground(env=None) -> None
130
+ # Blocking. For dev/debug.
131
+ ```
132
+
133
+ `DaemonStatus` fields: `running`, `pid`, `exchanges`, `active_tickets`, `uptime_s`, `version`
134
+
135
+ ---
136
+
137
+ ### Tickets
138
+
139
+ ```python
140
+ bf.place(
141
+ exchange: str,
142
+ symbol: str,
143
+ strategy: str,
144
+ target_position: float, # positive = buy, negative = sell
145
+ time_constraint_ms: int,
146
+ client_ticket_id: str | None = None, # idempotency key
147
+ ) -> Ticket
148
+
149
+ bf.query(
150
+ status: str | None = None, # "NEW" | "OPEN" | "COMPLETE" | "CANCEL"
151
+ symbol: str | None = None,
152
+ ticket_id: str | None = None,
153
+ from_ms: int | None = None,
154
+ to_ms: int | None = None,
155
+ limit: int = 100,
156
+ ) -> list[Ticket]
157
+
158
+ bf.cancel(ticket_id: str) -> None
159
+ # Raises TicketNotFound if ticket doesn't exist.
160
+
161
+ bf.cancel_all() -> int
162
+ # Returns number of cancelled tickets.
163
+ ```
164
+
165
+ `Ticket` fields: `ticket_id`, `status`, `exchange`, `symbol`, `strategy`, `target_position`, `executed_position`, `time_constraint_ms`, `start_time_ms`, `last_update_time_ms`, `is_expired`, `cancel_reason`
166
+
167
+ **Auto-cancel**: placing a new ticket for the same `exchange+symbol` automatically cancels existing `NEW` tickets for that pair.
168
+
169
+ ---
170
+
171
+ ### Context Manager
172
+
173
+ ```python
174
+ with Blockfill(binary_path=..., data_dir=...) as bf:
175
+ bf.start(env={"BLOCKFILL_API_KEY": "..."})
176
+ ticket = bf.place(...)
177
+ # daemon is stopped on exit
178
+ ```
179
+
180
+ ---
181
+
182
+ ### Exceptions
183
+
184
+ | Exception | When |
185
+ | ------------------------- | --------------------------------------------- |
186
+ | `BinaryNotFound` | binary not found, call `install()` first |
187
+ | `DaemonNotRunning` | daemon socket not found or unreachable |
188
+ | `DaemonStartTimeout` | `start()` timed out waiting for daemon |
189
+ | `RpcError(code, message)` | daemon returned a JSON-RPC error |
190
+ | `TicketNotFound` | `cancel()` called with non-existent ticket_id |
191
+ | `CredentialsError` | invalid exchange name in `set_credentials()` |
192
+ | `InstallError` | binary download failed |
193
+
194
+ ---
195
+
196
+ ## Patterns
197
+
198
+ ### Strategy system integration
199
+
200
+ ```python
201
+ from blockfill import Blockfill, DaemonNotRunning
202
+
203
+ bf = Blockfill(binary_path="/path/to/blockfill")
204
+
205
+ # On startup
206
+ if not bf.is_running():
207
+ bf.start(env={"BLOCKFILL_API_KEY": "..."})
208
+ bf.health()
209
+
210
+ # On each signal
211
+ ticket = bf.place(
212
+ exchange="binance-futures",
213
+ symbol=symbol,
214
+ strategy="maker_l2",
215
+ target_position=position,
216
+ time_constraint_ms=300_000,
217
+ )
218
+ ```
219
+
220
+ ### Idempotent placement (safe to retry)
221
+
222
+ ```python
223
+ import uuid
224
+
225
+ key = str(uuid.uuid4()) # generate once, reuse on retry
226
+
227
+ ticket = bf.place(
228
+ exchange="binance-futures",
229
+ symbol="btcusdt",
230
+ strategy="maker_l2",
231
+ target_position=0.1,
232
+ time_constraint_ms=300_000,
233
+ client_ticket_id=key,
234
+ )
235
+ ```
236
+
237
+ ### Check open positions
238
+
239
+ ```python
240
+ open_tickets = bf.query(status="NEW") + bf.query(status="OPEN")
241
+ for t in open_tickets:
242
+ print(t.symbol, t.target_position, t.executed_position)
243
+ ```
244
+
245
+ ---
246
+
247
+ ## AI Agent Usage
248
+
249
+ The SDK is designed for programmatic use by AI agents (Claude, GPT, etc.).
250
+
251
+ ```python
252
+ import sys
253
+ sys.path.insert(0, "/path/to/python-sdk")
254
+
255
+ import os
256
+ os.environ["BLOCKFILL_API_KEY"] = "your_api_key"
257
+
258
+ from blockfill import Blockfill, DaemonNotRunning, TicketNotFound
259
+
260
+ bf = Blockfill(
261
+ binary_path="/path/to/blockfill",
262
+ data_dir="/path/to/data_dir",
263
+ )
264
+
265
+ if not bf.is_running():
266
+ bf.start(env={"BLOCKFILL_API_KEY": os.environ["BLOCKFILL_API_KEY"]})
267
+
268
+ bf.health() # raises if daemon not ready
269
+ ```
270
+
271
+ Key points for agents:
272
+
273
+ - Always call `bf.health()` before placing tickets
274
+ - Use `client_ticket_id=uuid.uuid4()` for idempotent retries
275
+ - `place()` auto-cancels existing NEW tickets for the same exchange+symbol
276
+ - `query()` returns data from qtex MongoDB (not exchange realtime)
277
+
278
+ ---
279
+
280
+ ## Directory Structure
281
+
282
+ ```
283
+ ~/.blockfill/
284
+ ├── config.toml # credentials + qtex endpoint (chmod 0600)
285
+ ├── bin/
286
+ │ └── blockfill # binary
287
+ ├── runtime/
288
+ │ ├── daemon.sock # UDS socket (CLI ↔ daemon IPC)
289
+ │ ├── daemon.pid # PID file
290
+ │ └── daemon.log # daemon logs
291
+ └── trading-log/ # Channel B upload retry buffer
292
+ ```
293
+
294
+ ## Supported Exchanges
295
+
296
+ | Exchange | Value |
297
+ | --------------- | ------------------- |
298
+ | Binance Futures | `"binance-futures"` |
299
+ | OKX Swap | `"okx-swap"` |
@@ -0,0 +1,288 @@
1
+ # blockfill Python SDK
2
+
3
+ Python wrapper for the [blockfill](../executor/) execution daemon. Covers the full lifecycle: install binary, configure credentials, manage daemon, place/query/cancel tickets.
4
+
5
+ ## Requirements
6
+
7
+ - Python 3.10+
8
+ - blockfill binary (see [Install](#install))
9
+ - blockfill daemon running (see [Daemon](#daemon))
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ pip install blockfill
15
+ # or from source
16
+ pip install -e /path/to/python-sdk
17
+ ```
18
+
19
+ ## Quickstart
20
+
21
+ ```python
22
+ from blockfill import Blockfill
23
+
24
+ bf = Blockfill(
25
+ binary_path="/path/to/blockfill", # or ~/.blockfill/bin/blockfill
26
+ data_dir="~/.blockfill",
27
+ )
28
+
29
+ # First-time setup
30
+ bf.set_credentials("binance-futures", api_key="...", api_secret="...")
31
+ bf.set_qtex_endpoint("https://qtex.example.com")
32
+
33
+ # Start daemon
34
+ bf.start(env={"BLOCKFILL_API_KEY": "..."})
35
+ bf.health()
36
+
37
+ # Place a ticket
38
+ ticket = bf.place(
39
+ exchange="binance-futures",
40
+ symbol="btcusdt",
41
+ strategy="maker_l2",
42
+ target_position=0.1,
43
+ time_constraint_ms=300_000,
44
+ )
45
+ print(ticket.ticket_id, ticket.status) # tkt_xxx NEW
46
+
47
+ # Query
48
+ tickets = bf.query(status="NEW")
49
+
50
+ # Cancel
51
+ bf.cancel(ticket.ticket_id)
52
+
53
+ # Stop daemon
54
+ bf.stop()
55
+ ```
56
+
57
+ ---
58
+
59
+ ## API Reference
60
+
61
+ ### `Blockfill(binary_path, data_dir, timeout_s)`
62
+
63
+ | Parameter | Default | Description |
64
+ | ------------- | ---------------------------- | ------------------------------------- |
65
+ | `binary_path` | `~/.blockfill/bin/blockfill` | Path to blockfill binary |
66
+ | `data_dir` | `~/.blockfill` | Data directory (config, socket, logs) |
67
+ | `timeout_s` | `10.0` | RPC call timeout (seconds) |
68
+
69
+ ---
70
+
71
+ ### Install & Version
72
+
73
+ ```python
74
+ bf.install(version="latest", force=False) -> str
75
+ # Returns installed version string.
76
+ # If binary already exists and force=False, skips download and returns current version.
77
+
78
+ bf.version() -> str
79
+ # Returns "blockfill 0.1.0"
80
+ ```
81
+
82
+ ---
83
+
84
+ ### Credentials
85
+
86
+ ```python
87
+ bf.set_credentials(
88
+ exchange: str, # "binance-futures" | "okx-swap"
89
+ api_key: str,
90
+ api_secret: str,
91
+ api_passphrase: str | None = None, # OKX only
92
+ ) -> None
93
+ # Writes to {data_dir}/config.toml (chmod 0600)
94
+
95
+ bf.set_qtex_endpoint(endpoint: str) -> None
96
+ # e.g. bf.set_qtex_endpoint("https://qtex.example.com")
97
+ ```
98
+
99
+ ---
100
+
101
+ ### Daemon
102
+
103
+ ```python
104
+ bf.start(wait_timeout_s=10.0, env=None) -> None
105
+ # Starts daemon in background. No-op if already running.
106
+ # env: extra environment variables (e.g. {"BLOCKFILL_API_KEY": "..."})
107
+
108
+ bf.stop(wait_timeout_s=5.0) -> None
109
+ # Graceful shutdown. No-op if not running.
110
+
111
+ bf.restart() -> None
112
+
113
+ bf.is_running() -> bool
114
+
115
+ bf.health() -> DaemonStatus
116
+ # Raises DaemonNotRunning if daemon is not up.
117
+
118
+ bf.run_foreground(env=None) -> None
119
+ # Blocking. For dev/debug.
120
+ ```
121
+
122
+ `DaemonStatus` fields: `running`, `pid`, `exchanges`, `active_tickets`, `uptime_s`, `version`
123
+
124
+ ---
125
+
126
+ ### Tickets
127
+
128
+ ```python
129
+ bf.place(
130
+ exchange: str,
131
+ symbol: str,
132
+ strategy: str,
133
+ target_position: float, # positive = buy, negative = sell
134
+ time_constraint_ms: int,
135
+ client_ticket_id: str | None = None, # idempotency key
136
+ ) -> Ticket
137
+
138
+ bf.query(
139
+ status: str | None = None, # "NEW" | "OPEN" | "COMPLETE" | "CANCEL"
140
+ symbol: str | None = None,
141
+ ticket_id: str | None = None,
142
+ from_ms: int | None = None,
143
+ to_ms: int | None = None,
144
+ limit: int = 100,
145
+ ) -> list[Ticket]
146
+
147
+ bf.cancel(ticket_id: str) -> None
148
+ # Raises TicketNotFound if ticket doesn't exist.
149
+
150
+ bf.cancel_all() -> int
151
+ # Returns number of cancelled tickets.
152
+ ```
153
+
154
+ `Ticket` fields: `ticket_id`, `status`, `exchange`, `symbol`, `strategy`, `target_position`, `executed_position`, `time_constraint_ms`, `start_time_ms`, `last_update_time_ms`, `is_expired`, `cancel_reason`
155
+
156
+ **Auto-cancel**: placing a new ticket for the same `exchange+symbol` automatically cancels existing `NEW` tickets for that pair.
157
+
158
+ ---
159
+
160
+ ### Context Manager
161
+
162
+ ```python
163
+ with Blockfill(binary_path=..., data_dir=...) as bf:
164
+ bf.start(env={"BLOCKFILL_API_KEY": "..."})
165
+ ticket = bf.place(...)
166
+ # daemon is stopped on exit
167
+ ```
168
+
169
+ ---
170
+
171
+ ### Exceptions
172
+
173
+ | Exception | When |
174
+ | ------------------------- | --------------------------------------------- |
175
+ | `BinaryNotFound` | binary not found, call `install()` first |
176
+ | `DaemonNotRunning` | daemon socket not found or unreachable |
177
+ | `DaemonStartTimeout` | `start()` timed out waiting for daemon |
178
+ | `RpcError(code, message)` | daemon returned a JSON-RPC error |
179
+ | `TicketNotFound` | `cancel()` called with non-existent ticket_id |
180
+ | `CredentialsError` | invalid exchange name in `set_credentials()` |
181
+ | `InstallError` | binary download failed |
182
+
183
+ ---
184
+
185
+ ## Patterns
186
+
187
+ ### Strategy system integration
188
+
189
+ ```python
190
+ from blockfill import Blockfill, DaemonNotRunning
191
+
192
+ bf = Blockfill(binary_path="/path/to/blockfill")
193
+
194
+ # On startup
195
+ if not bf.is_running():
196
+ bf.start(env={"BLOCKFILL_API_KEY": "..."})
197
+ bf.health()
198
+
199
+ # On each signal
200
+ ticket = bf.place(
201
+ exchange="binance-futures",
202
+ symbol=symbol,
203
+ strategy="maker_l2",
204
+ target_position=position,
205
+ time_constraint_ms=300_000,
206
+ )
207
+ ```
208
+
209
+ ### Idempotent placement (safe to retry)
210
+
211
+ ```python
212
+ import uuid
213
+
214
+ key = str(uuid.uuid4()) # generate once, reuse on retry
215
+
216
+ ticket = bf.place(
217
+ exchange="binance-futures",
218
+ symbol="btcusdt",
219
+ strategy="maker_l2",
220
+ target_position=0.1,
221
+ time_constraint_ms=300_000,
222
+ client_ticket_id=key,
223
+ )
224
+ ```
225
+
226
+ ### Check open positions
227
+
228
+ ```python
229
+ open_tickets = bf.query(status="NEW") + bf.query(status="OPEN")
230
+ for t in open_tickets:
231
+ print(t.symbol, t.target_position, t.executed_position)
232
+ ```
233
+
234
+ ---
235
+
236
+ ## AI Agent Usage
237
+
238
+ The SDK is designed for programmatic use by AI agents (Claude, GPT, etc.).
239
+
240
+ ```python
241
+ import sys
242
+ sys.path.insert(0, "/path/to/python-sdk")
243
+
244
+ import os
245
+ os.environ["BLOCKFILL_API_KEY"] = "your_api_key"
246
+
247
+ from blockfill import Blockfill, DaemonNotRunning, TicketNotFound
248
+
249
+ bf = Blockfill(
250
+ binary_path="/path/to/blockfill",
251
+ data_dir="/path/to/data_dir",
252
+ )
253
+
254
+ if not bf.is_running():
255
+ bf.start(env={"BLOCKFILL_API_KEY": os.environ["BLOCKFILL_API_KEY"]})
256
+
257
+ bf.health() # raises if daemon not ready
258
+ ```
259
+
260
+ Key points for agents:
261
+
262
+ - Always call `bf.health()` before placing tickets
263
+ - Use `client_ticket_id=uuid.uuid4()` for idempotent retries
264
+ - `place()` auto-cancels existing NEW tickets for the same exchange+symbol
265
+ - `query()` returns data from qtex MongoDB (not exchange realtime)
266
+
267
+ ---
268
+
269
+ ## Directory Structure
270
+
271
+ ```
272
+ ~/.blockfill/
273
+ ├── config.toml # credentials + qtex endpoint (chmod 0600)
274
+ ├── bin/
275
+ │ └── blockfill # binary
276
+ ├── runtime/
277
+ │ ├── daemon.sock # UDS socket (CLI ↔ daemon IPC)
278
+ │ ├── daemon.pid # PID file
279
+ │ └── daemon.log # daemon logs
280
+ └── trading-log/ # Channel B upload retry buffer
281
+ ```
282
+
283
+ ## Supported Exchanges
284
+
285
+ | Exchange | Value |
286
+ | --------------- | ------------------- |
287
+ | Binance Futures | `"binance-futures"` |
288
+ | OKX Swap | `"okx-swap"` |
@@ -0,0 +1,24 @@
1
+ from .client import Blockfill
2
+ from .exceptions import (
3
+ BinaryNotFound,
4
+ CredentialsError,
5
+ DaemonNotRunning,
6
+ DaemonStartTimeout,
7
+ InstallError,
8
+ RpcError,
9
+ TicketNotFound,
10
+ )
11
+ from .models import DaemonStatus, Ticket
12
+
13
+ __all__ = [
14
+ "Blockfill",
15
+ "Ticket",
16
+ "DaemonStatus",
17
+ "BinaryNotFound",
18
+ "CredentialsError",
19
+ "DaemonNotRunning",
20
+ "DaemonStartTimeout",
21
+ "InstallError",
22
+ "RpcError",
23
+ "TicketNotFound",
24
+ ]