trading-cli 0.3.0__tar.gz → 0.3.1__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.
- {trading_cli-0.3.0/trading_cli.egg-info → trading_cli-0.3.1}/PKG-INFO +23 -73
- {trading_cli-0.3.0 → trading_cli-0.3.1}/README.md +22 -72
- {trading_cli-0.3.0 → trading_cli-0.3.1}/SKILL.md +4 -3
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/__init__.py +1 -1
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/client.py +23 -2
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/init_cmd.py +2 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/onchain.py +71 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/pyproject.toml +1 -1
- {trading_cli-0.3.0 → trading_cli-0.3.1/trading_cli.egg-info}/PKG-INFO +23 -73
- {trading_cli-0.3.0 → trading_cli-0.3.1}/EXCHANGES.md +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/LICENSE +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/MANIFEST.in +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/examples/bots_alpaca.sh +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/examples/bots_binance.sh +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/examples/bots_bybit.sh +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/examples/bots_coinbase.sh +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/examples/bots_dex_perps.sh +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/examples/bots_hyperliquid.sh +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/examples/bots_ibkr.sh +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/examples/bots_kraken.sh +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/examples/bots_kucoin.sh +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/examples/bots_okx.sh +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/examples/forward_test_all.sh +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/examples/paper_quickstart.sh +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/examples/polymarket.sh +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/examples/repl_session.sh +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/examples/swaps_and_wallets.sh +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/__main__.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/__init__.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/apikey.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/backtest.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/bots.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/config.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/dex.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/direct.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/execution.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/markets.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/mcp_cmd.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/polymarket.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/repl.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/strategy.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/swap.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/commands/wallet.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/config_store.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/direct.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/main.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/mcp_server.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/output.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/fastbooks_cli/strategies/__init__.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/setup.cfg +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/tests/README.md +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/tests/__init__.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/tests/conftest.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/tests/test_backtest.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/tests/test_bots_per_exchange.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/tests/test_cli.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/tests/test_dex.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/tests/test_e2e_flows.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/tests/test_execution_per_venue.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/tests/test_paper_flows_per_exchange.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/tests/test_polymarket.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/tests/test_repl.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/tests/test_strategy.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/tests/test_stress.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/tests/test_swap.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/tests/test_wallet_creation.py +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/trading_cli.egg-info/SOURCES.txt +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/trading_cli.egg-info/dependency_links.txt +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/trading_cli.egg-info/entry_points.txt +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/trading_cli.egg-info/requires.txt +0 -0
- {trading_cli-0.3.0 → trading_cli-0.3.1}/trading_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: trading-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Trade any exchange from the command line — agent-native trading CLI
|
|
5
5
|
Author: FastBooks
|
|
6
6
|
License: MIT
|
|
@@ -67,39 +67,42 @@ human-readable tables by default, machine-readable JSON with `--json`.
|
|
|
67
67
|
|
|
68
68
|
## Install
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
One-liner:
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
|
-
pipx install
|
|
73
|
+
pipx install "trading-cli[agent]" # recommended (isolated); base: pip install trading-cli
|
|
74
74
|
fastbooks --help
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
`trading-cli` is the base client (`click` + `requests`). The `[agent]` extra adds `ccxt`
|
|
78
|
+
(100+ exchanges, standalone) and the MCP server. Commands installed: `fastbooks`, `trading`, `fastbooks-mcp`.
|
|
79
|
+
Requires Python ≥ 3.10.
|
|
78
80
|
|
|
79
|
-
|
|
80
|
-
cd cli && pip install -e . # installs the `fastbooks` command
|
|
81
|
-
```
|
|
81
|
+
## What runs where
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
The pip package is a **thin client** — it does **not** run FastBooks' servers. On *your*
|
|
84
|
+
machine it runs: the CLI, the standalone **`direct`** engine (ccxt — 100+ exchanges, keyless
|
|
85
|
+
public data + trading on *your own* keys, no backend needed), and the **MCP server**.
|
|
84
86
|
|
|
85
|
-
|
|
87
|
+
The **FastBooks platform** (aggregated multi-asset data, unified execution, bots, signals) is a
|
|
88
|
+
**hosted service** — the CLI points at it **by default**, no setup needed:
|
|
86
89
|
|
|
87
|
-
|
|
90
|
+
| Service | Default (hosted) | Override env var |
|
|
91
|
+
|---------|------------------|------------------|
|
|
92
|
+
| Routing API (markets, execution, keys) | `https://app.fastbooks.exchange` | `FASTBOOKS_ROUTING_URL` |
|
|
93
|
+
| Bots service (deploy, forward-test) | `https://app.fastbooks.exchange` | `FASTBOOKS_BOTS_URL` |
|
|
88
94
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
> The CLI already targets the hosted FastBooks API — you don't run those services yourself.
|
|
96
|
+
> Just mint a key (`fastbooks apikey create`, free) and set `FASTBOOKS_API_KEY`; platform data
|
|
97
|
+
> is **metered per key**. For trading you never send exchange keys to the server — the CLI trades
|
|
98
|
+
> client-side via `direct` with your own keys. Self-hosting the backend? Override the env vars to
|
|
99
|
+
> `http://localhost:3002` / `:8003`.
|
|
93
100
|
|
|
94
101
|
```bash
|
|
95
|
-
fastbooks config show # show resolved URLs
|
|
96
|
-
fastbooks config
|
|
102
|
+
fastbooks config show # show resolved URLs + stored config
|
|
103
|
+
fastbooks config health # ping the hosted services
|
|
97
104
|
```
|
|
98
105
|
|
|
99
|
-
Auth: FastBooks platform keys (`apikey`) are **fully self-service — no admin
|
|
100
|
-
token**. The only token you may need is `FASTBOOKS_API_TOKEN` (a JWT), and only
|
|
101
|
-
for storing exchange keys & saved backtests.
|
|
102
|
-
|
|
103
106
|
---
|
|
104
107
|
|
|
105
108
|
## Quickstart — the four core flows
|
|
@@ -254,56 +257,3 @@ FASTBOOKS_E2E=1 python3 -m pytest -q # live smoke against running service
|
|
|
254
257
|
|
|
255
258
|
See [tests/README.md](tests/README.md). The capability suite asserts the CLI
|
|
256
259
|
hits the correct backend endpoints (method + path + auth) for the four flows.
|
|
257
|
-
|
|
258
|
-
---
|
|
259
|
-
|
|
260
|
-
## Publishing to PyPI
|
|
261
|
-
|
|
262
|
-
The package builds from `pyproject.toml` (PEP 621, setuptools backend) — no
|
|
263
|
-
Poetry needed. One-time tooling:
|
|
264
|
-
|
|
265
|
-
```bash
|
|
266
|
-
pip install --upgrade build twine
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
Release steps (run from `cli/`):
|
|
270
|
-
|
|
271
|
-
```bash
|
|
272
|
-
# 1. Bump the version in pyproject.toml (e.g. 0.2.0 -> 0.2.1)
|
|
273
|
-
# 2. Build sdist + wheel into dist/
|
|
274
|
-
python3 -m build
|
|
275
|
-
|
|
276
|
-
# 3. Sanity-check the metadata
|
|
277
|
-
twine check dist/*
|
|
278
|
-
|
|
279
|
-
# 4. Upload to TestPyPI first (recommended), then verify the install
|
|
280
|
-
twine upload --repository testpypi dist/*
|
|
281
|
-
pipx install --index-url https://test.pypi.org/simple/ fastbooks-cli
|
|
282
|
-
|
|
283
|
-
# 5. Upload to real PyPI
|
|
284
|
-
twine upload dist/*
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
Auth uses an API token (create at https://pypi.org/manage/account/token/). Put it in
|
|
288
|
-
`~/.pypirc` or pass it as the password with username `__token__`:
|
|
289
|
-
|
|
290
|
-
```ini
|
|
291
|
-
# ~/.pypirc
|
|
292
|
-
[pypi]
|
|
293
|
-
username = __token__
|
|
294
|
-
password = pypi-AgEN...your-token...
|
|
295
|
-
[testpypi]
|
|
296
|
-
username = __token__
|
|
297
|
-
password = pypi-AgEN...your-testpypi-token...
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
Notes:
|
|
301
|
-
- The project name `fastbooks-cli` must be free on PyPI (check
|
|
302
|
-
https://pypi.org/project/fastbooks-cli/); the `fastbooks` command name is unaffected by that.
|
|
303
|
-
- `MANIFEST.in` ships `README.md`, `SKILL.md`, `EXCHANGES.md`, `LICENSE`, and `examples/`
|
|
304
|
-
in the sdist. Only the `fastbooks_cli` package is included — **no strategy logic**.
|
|
305
|
-
- Each upload version is immutable; bump the version for every release.
|
|
306
|
-
- For automated releases, use the PyPI **Trusted Publisher** (OIDC) GitHub Action
|
|
307
|
-
instead of a long-lived token.
|
|
308
|
-
- The proprietary `fastbooks-clistrategies` package is built the same way but
|
|
309
|
-
published privately (or installed from a Git URL), never to public PyPI.
|
|
@@ -31,39 +31,42 @@ human-readable tables by default, machine-readable JSON with `--json`.
|
|
|
31
31
|
|
|
32
32
|
## Install
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
One-liner:
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
|
-
pipx install
|
|
37
|
+
pipx install "trading-cli[agent]" # recommended (isolated); base: pip install trading-cli
|
|
38
38
|
fastbooks --help
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
`trading-cli` is the base client (`click` + `requests`). The `[agent]` extra adds `ccxt`
|
|
42
|
+
(100+ exchanges, standalone) and the MCP server. Commands installed: `fastbooks`, `trading`, `fastbooks-mcp`.
|
|
43
|
+
Requires Python ≥ 3.10.
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
cd cli && pip install -e . # installs the `fastbooks` command
|
|
45
|
-
```
|
|
45
|
+
## What runs where
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
The pip package is a **thin client** — it does **not** run FastBooks' servers. On *your*
|
|
48
|
+
machine it runs: the CLI, the standalone **`direct`** engine (ccxt — 100+ exchanges, keyless
|
|
49
|
+
public data + trading on *your own* keys, no backend needed), and the **MCP server**.
|
|
48
50
|
|
|
49
|
-
|
|
51
|
+
The **FastBooks platform** (aggregated multi-asset data, unified execution, bots, signals) is a
|
|
52
|
+
**hosted service** — the CLI points at it **by default**, no setup needed:
|
|
50
53
|
|
|
51
|
-
|
|
54
|
+
| Service | Default (hosted) | Override env var |
|
|
55
|
+
|---------|------------------|------------------|
|
|
56
|
+
| Routing API (markets, execution, keys) | `https://app.fastbooks.exchange` | `FASTBOOKS_ROUTING_URL` |
|
|
57
|
+
| Bots service (deploy, forward-test) | `https://app.fastbooks.exchange` | `FASTBOOKS_BOTS_URL` |
|
|
52
58
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
> The CLI already targets the hosted FastBooks API — you don't run those services yourself.
|
|
60
|
+
> Just mint a key (`fastbooks apikey create`, free) and set `FASTBOOKS_API_KEY`; platform data
|
|
61
|
+
> is **metered per key**. For trading you never send exchange keys to the server — the CLI trades
|
|
62
|
+
> client-side via `direct` with your own keys. Self-hosting the backend? Override the env vars to
|
|
63
|
+
> `http://localhost:3002` / `:8003`.
|
|
57
64
|
|
|
58
65
|
```bash
|
|
59
|
-
fastbooks config show # show resolved URLs
|
|
60
|
-
fastbooks config
|
|
66
|
+
fastbooks config show # show resolved URLs + stored config
|
|
67
|
+
fastbooks config health # ping the hosted services
|
|
61
68
|
```
|
|
62
69
|
|
|
63
|
-
Auth: FastBooks platform keys (`apikey`) are **fully self-service — no admin
|
|
64
|
-
token**. The only token you may need is `FASTBOOKS_API_TOKEN` (a JWT), and only
|
|
65
|
-
for storing exchange keys & saved backtests.
|
|
66
|
-
|
|
67
70
|
---
|
|
68
71
|
|
|
69
72
|
## Quickstart — the four core flows
|
|
@@ -218,56 +221,3 @@ FASTBOOKS_E2E=1 python3 -m pytest -q # live smoke against running service
|
|
|
218
221
|
|
|
219
222
|
See [tests/README.md](tests/README.md). The capability suite asserts the CLI
|
|
220
223
|
hits the correct backend endpoints (method + path + auth) for the four flows.
|
|
221
|
-
|
|
222
|
-
---
|
|
223
|
-
|
|
224
|
-
## Publishing to PyPI
|
|
225
|
-
|
|
226
|
-
The package builds from `pyproject.toml` (PEP 621, setuptools backend) — no
|
|
227
|
-
Poetry needed. One-time tooling:
|
|
228
|
-
|
|
229
|
-
```bash
|
|
230
|
-
pip install --upgrade build twine
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
Release steps (run from `cli/`):
|
|
234
|
-
|
|
235
|
-
```bash
|
|
236
|
-
# 1. Bump the version in pyproject.toml (e.g. 0.2.0 -> 0.2.1)
|
|
237
|
-
# 2. Build sdist + wheel into dist/
|
|
238
|
-
python3 -m build
|
|
239
|
-
|
|
240
|
-
# 3. Sanity-check the metadata
|
|
241
|
-
twine check dist/*
|
|
242
|
-
|
|
243
|
-
# 4. Upload to TestPyPI first (recommended), then verify the install
|
|
244
|
-
twine upload --repository testpypi dist/*
|
|
245
|
-
pipx install --index-url https://test.pypi.org/simple/ fastbooks-cli
|
|
246
|
-
|
|
247
|
-
# 5. Upload to real PyPI
|
|
248
|
-
twine upload dist/*
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
Auth uses an API token (create at https://pypi.org/manage/account/token/). Put it in
|
|
252
|
-
`~/.pypirc` or pass it as the password with username `__token__`:
|
|
253
|
-
|
|
254
|
-
```ini
|
|
255
|
-
# ~/.pypirc
|
|
256
|
-
[pypi]
|
|
257
|
-
username = __token__
|
|
258
|
-
password = pypi-AgEN...your-token...
|
|
259
|
-
[testpypi]
|
|
260
|
-
username = __token__
|
|
261
|
-
password = pypi-AgEN...your-testpypi-token...
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
Notes:
|
|
265
|
-
- The project name `fastbooks-cli` must be free on PyPI (check
|
|
266
|
-
https://pypi.org/project/fastbooks-cli/); the `fastbooks` command name is unaffected by that.
|
|
267
|
-
- `MANIFEST.in` ships `README.md`, `SKILL.md`, `EXCHANGES.md`, `LICENSE`, and `examples/`
|
|
268
|
-
in the sdist. Only the `fastbooks_cli` package is included — **no strategy logic**.
|
|
269
|
-
- Each upload version is immutable; bump the version for every release.
|
|
270
|
-
- For automated releases, use the PyPI **Trusted Publisher** (OIDC) GitHub Action
|
|
271
|
-
instead of a long-lived token.
|
|
272
|
-
- The proprietary `fastbooks-clistrategies` package is built the same way but
|
|
273
|
-
published privately (or installed from a Git URL), never to public PyPI.
|
|
@@ -279,9 +279,10 @@ fastbooks --json wallet create-evm
|
|
|
279
279
|
|
|
280
280
|
| Variable | Description |
|
|
281
281
|
|----------|-------------|
|
|
282
|
-
| `FASTBOOKS_ROUTING_URL` | Routing API (default: `http://localhost:3002`) |
|
|
283
|
-
| `FASTBOOKS_BOTS_URL` | Bots service (default: `http://localhost:8003`) |
|
|
284
|
-
| `
|
|
282
|
+
| `FASTBOOKS_ROUTING_URL` | Routing API (default: `https://app.fastbooks.exchange`; self-host: `http://localhost:3002`) |
|
|
283
|
+
| `FASTBOOKS_BOTS_URL` | Bots service (default: `https://app.fastbooks.exchange`; self-host: `http://localhost:8003`) |
|
|
284
|
+
| `FASTBOOKS_API_KEY` | FastBooks data key (`fb_live_…`) — sent as `x-api-key`, metered per key. Mint: `fastbooks apikey create` |
|
|
285
|
+
| `FASTBOOKS_API_TOKEN` | JWT for authenticated routes (exchange keys, saved backtests, onchain) |
|
|
285
286
|
| `FASTBOOKS_EXPERIMENTAL` | Set to `1` to enable the `swap`/`dex`/`polymarket` groups |
|
|
286
287
|
| `ALPACA_API_KEY` | Alpaca API key |
|
|
287
288
|
| `ALPACA_API_SECRET` | Alpaca API secret |
|
|
@@ -9,8 +9,10 @@ from typing import Any
|
|
|
9
9
|
|
|
10
10
|
import requests
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
# Public hosted FastBooks API (this is our server). External users get it out of the box;
|
|
13
|
+
# self-hosters/devs override with FASTBOOKS_ROUTING_URL / FASTBOOKS_BOTS_URL (e.g. http://localhost:3002).
|
|
14
|
+
DEFAULT_ROUTING_URL = "https://app.fastbooks.exchange"
|
|
15
|
+
DEFAULT_BOTS_URL = "https://app.fastbooks.exchange"
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
def _stored_api_key() -> str | None:
|
|
@@ -342,6 +344,25 @@ class FastBooksClient:
|
|
|
342
344
|
def onchain_live_stop(self, strategy_id: str) -> Any:
|
|
343
345
|
return self.onchain_post("/api/exec/live/stop", {"strategyId": strategy_id})
|
|
344
346
|
|
|
347
|
+
# on-chain DEX swaps (real signing happens in the engine; keys stay in its local KeyStore)
|
|
348
|
+
def onchain_buy(self, dex: str, token_address: str, amount_sol: float, slippage_bps: int | None = None) -> Any:
|
|
349
|
+
body: dict[str, Any] = {"dex": dex, "tokenAddress": token_address, "amountSol": amount_sol}
|
|
350
|
+
if slippage_bps is not None:
|
|
351
|
+
body["slippageBps"] = slippage_bps
|
|
352
|
+
return self.onchain_post("/api/exec/buy", body)
|
|
353
|
+
|
|
354
|
+
def onchain_sell(self, dex: str, token_address: str, token_amount: str, slippage_bps: int | None = None) -> Any:
|
|
355
|
+
body: dict[str, Any] = {"dex": dex, "tokenAddress": token_address, "tokenAmount": str(token_amount)}
|
|
356
|
+
if slippage_bps is not None:
|
|
357
|
+
body["slippageBps"] = slippage_bps
|
|
358
|
+
return self.onchain_post("/api/exec/sell", body)
|
|
359
|
+
|
|
360
|
+
def onchain_evm_swap(self, chain: str, sell_token: str, buy_token: str, sell_amount: str, slippage_bps: int | None = None) -> Any:
|
|
361
|
+
body: dict[str, Any] = {"chain": chain, "sellToken": sell_token, "buyToken": buy_token, "sellAmount": str(sell_amount)}
|
|
362
|
+
if slippage_bps is not None:
|
|
363
|
+
body["slippageBps"] = slippage_bps
|
|
364
|
+
return self.onchain_post("/api/exec/evm", body)
|
|
365
|
+
|
|
345
366
|
def fastbooks_api_key_info(self, api_key: str) -> dict:
|
|
346
367
|
return self._get(self.routing_url, "/api/keys/me", headers={"x-api-key": api_key})
|
|
347
368
|
|
|
@@ -21,6 +21,8 @@ CATALOG = [
|
|
|
21
21
|
["binance", "bybit", "okx", "kraken", "coinbase", "kucoin", "bitget", "gate", "mexc", "htx"], "ccxt"),
|
|
22
22
|
("On-chain perps / DEX — via ccxt (hyperliquid/dydx/… use a wallet key as 'secret')",
|
|
23
23
|
["hyperliquid", "dydx", "paradex", "apex", "woofipro"], "ccxt"),
|
|
24
|
+
("Options & derivatives — via ccxt",
|
|
25
|
+
["deribit", "okx", "bybit"], "ccxt"),
|
|
24
26
|
("Stocks — FastBooks platform (connect: `fastbooks --token <JWT> wallet add ...`)",
|
|
25
27
|
["alpaca", "ibkr"], "platform"),
|
|
26
28
|
("Forex — FastBooks platform",
|
|
@@ -121,3 +121,74 @@ def stop_cmd(ctx: click.Context, strategy_id: str):
|
|
|
121
121
|
except Exception as e: # noqa: BLE001
|
|
122
122
|
emit_error(ctx, str(e))
|
|
123
123
|
ctx.exit(1)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# ── DEX swaps (real on-chain execution; signing happens in the engine's KeyStore) ──
|
|
127
|
+
|
|
128
|
+
def _confirm_live(ctx, msg: str, yes: bool) -> None:
|
|
129
|
+
if not yes and not ctx.find_root().params.get("json_output"):
|
|
130
|
+
click.confirm(msg, abort=True)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@onchain.command("buy")
|
|
134
|
+
@click.argument("dex", type=click.Choice(["jupiter", "pumpfun"]))
|
|
135
|
+
@click.argument("token_address")
|
|
136
|
+
@click.argument("amount_sol", type=float)
|
|
137
|
+
@click.option("--slippage-bps", type=int, default=None)
|
|
138
|
+
@click.option("--yes", is_flag=True, help="Skip the real-funds confirmation.")
|
|
139
|
+
@click.pass_context
|
|
140
|
+
def buy_cmd(ctx, dex, token_address, amount_sol, slippage_bps, yes):
|
|
141
|
+
"""DEX swap SOL -> token (Jupiter aggregator or Pump.fun) — REAL funds.
|
|
142
|
+
|
|
143
|
+
e.g. onchain buy jupiter <MINT> 0.05
|
|
144
|
+
"""
|
|
145
|
+
client: FastBooksClient = ctx.obj
|
|
146
|
+
_confirm_live(ctx, f"LIVE swap: buy {amount_sol} SOL of {token_address[:8]}… via {dex}?", yes)
|
|
147
|
+
try:
|
|
148
|
+
emit(ctx, client.onchain_buy(dex, token_address, amount_sol, slippage_bps))
|
|
149
|
+
except Exception as e: # noqa: BLE001
|
|
150
|
+
emit_error(ctx, str(e))
|
|
151
|
+
ctx.exit(1)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@onchain.command("sell")
|
|
155
|
+
@click.argument("dex", type=click.Choice(["jupiter", "pumpfun"]))
|
|
156
|
+
@click.argument("token_address")
|
|
157
|
+
@click.argument("token_amount")
|
|
158
|
+
@click.option("--slippage-bps", type=int, default=None)
|
|
159
|
+
@click.option("--yes", is_flag=True, help="Skip the real-funds confirmation.")
|
|
160
|
+
@click.pass_context
|
|
161
|
+
def sell_cmd(ctx, dex, token_address, token_amount, slippage_bps, yes):
|
|
162
|
+
"""DEX swap token -> SOL (Jupiter or Pump.fun) — REAL funds. token_amount is raw base units.
|
|
163
|
+
|
|
164
|
+
e.g. onchain sell jupiter <MINT> 413433846822
|
|
165
|
+
"""
|
|
166
|
+
client: FastBooksClient = ctx.obj
|
|
167
|
+
_confirm_live(ctx, f"LIVE swap: sell {token_amount} of {token_address[:8]}… via {dex}?", yes)
|
|
168
|
+
try:
|
|
169
|
+
emit(ctx, client.onchain_sell(dex, token_address, token_amount, slippage_bps))
|
|
170
|
+
except Exception as e: # noqa: BLE001
|
|
171
|
+
emit_error(ctx, str(e))
|
|
172
|
+
ctx.exit(1)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@onchain.command("swap-evm")
|
|
176
|
+
@click.argument("chain", type=click.Choice(["arbitrum", "bsc"]))
|
|
177
|
+
@click.argument("sell_token")
|
|
178
|
+
@click.argument("buy_token")
|
|
179
|
+
@click.argument("sell_amount")
|
|
180
|
+
@click.option("--slippage-bps", type=int, default=None)
|
|
181
|
+
@click.option("--yes", is_flag=True, help="Skip the real-funds confirmation.")
|
|
182
|
+
@click.pass_context
|
|
183
|
+
def swap_evm_cmd(ctx, chain, sell_token, buy_token, sell_amount, slippage_bps, yes):
|
|
184
|
+
"""EVM DEX swap via 0x (Uniswap-class) on arbitrum/bsc — REAL funds. sell_amount in base units.
|
|
185
|
+
|
|
186
|
+
e.g. onchain swap-evm arbitrum <USDC> <WETH> 1000000
|
|
187
|
+
"""
|
|
188
|
+
client: FastBooksClient = ctx.obj
|
|
189
|
+
_confirm_live(ctx, f"LIVE swap on {chain}: {sell_amount} {sell_token[:8]}… -> {buy_token[:8]}…?", yes)
|
|
190
|
+
try:
|
|
191
|
+
emit(ctx, client.onchain_evm_swap(chain, sell_token, buy_token, sell_amount, slippage_bps))
|
|
192
|
+
except Exception as e: # noqa: BLE001
|
|
193
|
+
emit_error(ctx, str(e))
|
|
194
|
+
ctx.exit(1)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: trading-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Trade any exchange from the command line — agent-native trading CLI
|
|
5
5
|
Author: FastBooks
|
|
6
6
|
License: MIT
|
|
@@ -67,39 +67,42 @@ human-readable tables by default, machine-readable JSON with `--json`.
|
|
|
67
67
|
|
|
68
68
|
## Install
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
One-liner:
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
|
-
pipx install
|
|
73
|
+
pipx install "trading-cli[agent]" # recommended (isolated); base: pip install trading-cli
|
|
74
74
|
fastbooks --help
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
`trading-cli` is the base client (`click` + `requests`). The `[agent]` extra adds `ccxt`
|
|
78
|
+
(100+ exchanges, standalone) and the MCP server. Commands installed: `fastbooks`, `trading`, `fastbooks-mcp`.
|
|
79
|
+
Requires Python ≥ 3.10.
|
|
78
80
|
|
|
79
|
-
|
|
80
|
-
cd cli && pip install -e . # installs the `fastbooks` command
|
|
81
|
-
```
|
|
81
|
+
## What runs where
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
The pip package is a **thin client** — it does **not** run FastBooks' servers. On *your*
|
|
84
|
+
machine it runs: the CLI, the standalone **`direct`** engine (ccxt — 100+ exchanges, keyless
|
|
85
|
+
public data + trading on *your own* keys, no backend needed), and the **MCP server**.
|
|
84
86
|
|
|
85
|
-
|
|
87
|
+
The **FastBooks platform** (aggregated multi-asset data, unified execution, bots, signals) is a
|
|
88
|
+
**hosted service** — the CLI points at it **by default**, no setup needed:
|
|
86
89
|
|
|
87
|
-
|
|
90
|
+
| Service | Default (hosted) | Override env var |
|
|
91
|
+
|---------|------------------|------------------|
|
|
92
|
+
| Routing API (markets, execution, keys) | `https://app.fastbooks.exchange` | `FASTBOOKS_ROUTING_URL` |
|
|
93
|
+
| Bots service (deploy, forward-test) | `https://app.fastbooks.exchange` | `FASTBOOKS_BOTS_URL` |
|
|
88
94
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
> The CLI already targets the hosted FastBooks API — you don't run those services yourself.
|
|
96
|
+
> Just mint a key (`fastbooks apikey create`, free) and set `FASTBOOKS_API_KEY`; platform data
|
|
97
|
+
> is **metered per key**. For trading you never send exchange keys to the server — the CLI trades
|
|
98
|
+
> client-side via `direct` with your own keys. Self-hosting the backend? Override the env vars to
|
|
99
|
+
> `http://localhost:3002` / `:8003`.
|
|
93
100
|
|
|
94
101
|
```bash
|
|
95
|
-
fastbooks config show # show resolved URLs
|
|
96
|
-
fastbooks config
|
|
102
|
+
fastbooks config show # show resolved URLs + stored config
|
|
103
|
+
fastbooks config health # ping the hosted services
|
|
97
104
|
```
|
|
98
105
|
|
|
99
|
-
Auth: FastBooks platform keys (`apikey`) are **fully self-service — no admin
|
|
100
|
-
token**. The only token you may need is `FASTBOOKS_API_TOKEN` (a JWT), and only
|
|
101
|
-
for storing exchange keys & saved backtests.
|
|
102
|
-
|
|
103
106
|
---
|
|
104
107
|
|
|
105
108
|
## Quickstart — the four core flows
|
|
@@ -254,56 +257,3 @@ FASTBOOKS_E2E=1 python3 -m pytest -q # live smoke against running service
|
|
|
254
257
|
|
|
255
258
|
See [tests/README.md](tests/README.md). The capability suite asserts the CLI
|
|
256
259
|
hits the correct backend endpoints (method + path + auth) for the four flows.
|
|
257
|
-
|
|
258
|
-
---
|
|
259
|
-
|
|
260
|
-
## Publishing to PyPI
|
|
261
|
-
|
|
262
|
-
The package builds from `pyproject.toml` (PEP 621, setuptools backend) — no
|
|
263
|
-
Poetry needed. One-time tooling:
|
|
264
|
-
|
|
265
|
-
```bash
|
|
266
|
-
pip install --upgrade build twine
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
Release steps (run from `cli/`):
|
|
270
|
-
|
|
271
|
-
```bash
|
|
272
|
-
# 1. Bump the version in pyproject.toml (e.g. 0.2.0 -> 0.2.1)
|
|
273
|
-
# 2. Build sdist + wheel into dist/
|
|
274
|
-
python3 -m build
|
|
275
|
-
|
|
276
|
-
# 3. Sanity-check the metadata
|
|
277
|
-
twine check dist/*
|
|
278
|
-
|
|
279
|
-
# 4. Upload to TestPyPI first (recommended), then verify the install
|
|
280
|
-
twine upload --repository testpypi dist/*
|
|
281
|
-
pipx install --index-url https://test.pypi.org/simple/ fastbooks-cli
|
|
282
|
-
|
|
283
|
-
# 5. Upload to real PyPI
|
|
284
|
-
twine upload dist/*
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
Auth uses an API token (create at https://pypi.org/manage/account/token/). Put it in
|
|
288
|
-
`~/.pypirc` or pass it as the password with username `__token__`:
|
|
289
|
-
|
|
290
|
-
```ini
|
|
291
|
-
# ~/.pypirc
|
|
292
|
-
[pypi]
|
|
293
|
-
username = __token__
|
|
294
|
-
password = pypi-AgEN...your-token...
|
|
295
|
-
[testpypi]
|
|
296
|
-
username = __token__
|
|
297
|
-
password = pypi-AgEN...your-testpypi-token...
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
Notes:
|
|
301
|
-
- The project name `fastbooks-cli` must be free on PyPI (check
|
|
302
|
-
https://pypi.org/project/fastbooks-cli/); the `fastbooks` command name is unaffected by that.
|
|
303
|
-
- `MANIFEST.in` ships `README.md`, `SKILL.md`, `EXCHANGES.md`, `LICENSE`, and `examples/`
|
|
304
|
-
in the sdist. Only the `fastbooks_cli` package is included — **no strategy logic**.
|
|
305
|
-
- Each upload version is immutable; bump the version for every release.
|
|
306
|
-
- For automated releases, use the PyPI **Trusted Publisher** (OIDC) GitHub Action
|
|
307
|
-
instead of a long-lived token.
|
|
308
|
-
- The proprietary `fastbooks-clistrategies` package is built the same way but
|
|
309
|
-
published privately (or installed from a Git URL), never to public PyPI.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|