qgist-cli 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.
- qgist_cli-0.1.0/.github/workflows/ci.yml +50 -0
- qgist_cli-0.1.0/.gitignore +46 -0
- qgist_cli-0.1.0/CHANGELOG.md +19 -0
- qgist_cli-0.1.0/LICENSE +21 -0
- qgist_cli-0.1.0/PKG-INFO +190 -0
- qgist_cli-0.1.0/README.md +172 -0
- qgist_cli-0.1.0/pyproject.toml +34 -0
- qgist_cli-0.1.0/src/qgist/__init__.py +0 -0
- qgist_cli-0.1.0/src/qgist/api.py +21 -0
- qgist_cli-0.1.0/src/qgist/cli.py +19 -0
- qgist_cli-0.1.0/src/qgist/commands/__init__.py +0 -0
- qgist_cli-0.1.0/src/qgist/commands/config.py +52 -0
- qgist_cli-0.1.0/src/qgist/commands/events.py +64 -0
- qgist_cli-0.1.0/src/qgist/commands/export.py +70 -0
- qgist_cli-0.1.0/src/qgist/commands/status.py +44 -0
- qgist_cli-0.1.0/src/qgist/config_store.py +28 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
tags: ["v*"]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
package-check:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
timeout-minutes: 15
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.11"
|
|
23
|
+
|
|
24
|
+
- uses: astral-sh/setup-uv@v5
|
|
25
|
+
|
|
26
|
+
- run: uv sync
|
|
27
|
+
- run: uv run qgist --help
|
|
28
|
+
- run: uv build
|
|
29
|
+
|
|
30
|
+
publish:
|
|
31
|
+
# Publishes to PyPI via the trusted publisher bound to this workflow
|
|
32
|
+
# (QuantGist-Technologies/quantgist-cli · ci.yml). Runs only on v* tags.
|
|
33
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
34
|
+
needs: package-check
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
timeout-minutes: 15
|
|
37
|
+
permissions:
|
|
38
|
+
id-token: write # required for OIDC trusted publishing
|
|
39
|
+
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
|
|
43
|
+
- uses: astral-sh/setup-uv@v5
|
|
44
|
+
|
|
45
|
+
- run: uv build
|
|
46
|
+
|
|
47
|
+
- name: Publish to PyPI
|
|
48
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
49
|
+
with:
|
|
50
|
+
skip-existing: true
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Byte-compiled / optimized
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
*.egg
|
|
11
|
+
.eggs/
|
|
12
|
+
wheels/
|
|
13
|
+
pip-wheel-metadata/
|
|
14
|
+
uv.lock
|
|
15
|
+
|
|
16
|
+
# Virtual environments
|
|
17
|
+
.venv/
|
|
18
|
+
venv/
|
|
19
|
+
env/
|
|
20
|
+
ENV/
|
|
21
|
+
|
|
22
|
+
# Test / coverage
|
|
23
|
+
.pytest_cache/
|
|
24
|
+
.coverage
|
|
25
|
+
htmlcov/
|
|
26
|
+
.tox/
|
|
27
|
+
.nox/
|
|
28
|
+
coverage.xml
|
|
29
|
+
*.cover
|
|
30
|
+
|
|
31
|
+
# Type checkers / linters
|
|
32
|
+
.mypy_cache/
|
|
33
|
+
.ruff_cache/
|
|
34
|
+
.pyre/
|
|
35
|
+
|
|
36
|
+
# Editors
|
|
37
|
+
.idea/
|
|
38
|
+
.vscode/
|
|
39
|
+
*.swp
|
|
40
|
+
*.swo
|
|
41
|
+
.DS_Store
|
|
42
|
+
|
|
43
|
+
# Local
|
|
44
|
+
.env
|
|
45
|
+
.env.local
|
|
46
|
+
CLAUDE.md
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## v0.1.0 — 2026-06-28
|
|
4
|
+
|
|
5
|
+
First PyPI release as **`qgist-cli`** (provides the `qgist` command).
|
|
6
|
+
|
|
7
|
+
### Notes
|
|
8
|
+
- Requires `quantgist>=0.7.1` (the SDK release that matches the current API: optional
|
|
9
|
+
country/currency, string-valued forecast/previous/actual, header-based rate limit).
|
|
10
|
+
- `events` tolerates events with no country; `export` caps at the API's 100/page limit and
|
|
11
|
+
exports the `symbols` column. Get a free key at https://quantgist.com.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- `qgist events [today|week]` — Rich table of upcoming events with impact color coding
|
|
15
|
+
- `qgist events --symbol`, `--country`, `--impact`, `--json` flags
|
|
16
|
+
- `qgist config set/get/show` — API key management in `~/.config/qgist/config.toml`
|
|
17
|
+
- `qgist export <keyword>` — CSV/JSON export of historical events with `--from`/`--to`/`--output` options
|
|
18
|
+
- `qgist status` — connection check, masked API key, plan info, rate limit remaining
|
|
19
|
+
- `QUANTGIST_API_KEY` environment variable support (overrides config file)
|
qgist_cli-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 QuantGist
|
|
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.
|
qgist_cli-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: qgist-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: CLI for the QuantGist macro event API — qgist events today
|
|
5
|
+
Project-URL: Homepage, https://quantgist.com
|
|
6
|
+
Project-URL: Repository, https://github.com/QuantGist-Technologies/quantgist-cli
|
|
7
|
+
Project-URL: Documentation, https://quantgist.com/docs
|
|
8
|
+
Author-email: QuantGist <dev@quantgist.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: cli,earnings,economic-calendar,macro,quantgist,trading
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Requires-Dist: quantgist>=0.7.1
|
|
14
|
+
Requires-Dist: rich>=13.0.0
|
|
15
|
+
Requires-Dist: tomli-w>=1.0.0
|
|
16
|
+
Requires-Dist: typer>=0.12.0
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# qgist
|
|
20
|
+
|
|
21
|
+
[](https://pypi.org/project/qgist-cli)
|
|
22
|
+
[](https://pypi.org/project/qgist-cli)
|
|
23
|
+
[](LICENSE)
|
|
24
|
+
|
|
25
|
+
Command-line interface for the [QuantGist](https://quantgist.com) macro event API. Check upcoming economic events, export historical data, and configure your key — all from the terminal.
|
|
26
|
+
|
|
27
|
+
The PyPI package is **`qgist-cli`**; it installs the **`qgist`** command.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install qgist-cli
|
|
35
|
+
# or (recommended — installs as an isolated tool)
|
|
36
|
+
uv tool install qgist-cli
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Quick start
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# 1. Set your API key (get one free at quantgist.com/signup)
|
|
45
|
+
qgist config set api-key qg_live_your_key_here
|
|
46
|
+
|
|
47
|
+
# 2. Check today's events
|
|
48
|
+
qgist events
|
|
49
|
+
|
|
50
|
+
# 3. Check this week's high-impact events
|
|
51
|
+
qgist events week --impact high
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Commands
|
|
57
|
+
|
|
58
|
+
### `qgist events [today|week]`
|
|
59
|
+
|
|
60
|
+
Show upcoming macro events in a formatted table.
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Usage: qgist events [PERIOD] [OPTIONS]
|
|
64
|
+
|
|
65
|
+
Arguments:
|
|
66
|
+
PERIOD today (default) | week
|
|
67
|
+
|
|
68
|
+
Options:
|
|
69
|
+
-s, --symbol TEXT Filter by symbol (e.g. XAUUSD)
|
|
70
|
+
-c, --country TEXT ISO country code (e.g. us, eu, gb)
|
|
71
|
+
-i, --impact TEXT Impact filter: low | medium | high
|
|
72
|
+
--json Output raw JSON
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Examples:**
|
|
76
|
+
```bash
|
|
77
|
+
qgist events # Today, all impacts
|
|
78
|
+
qgist events week # Next 7 days
|
|
79
|
+
qgist events week --impact high # This week, high-impact only
|
|
80
|
+
qgist events today --country us # Today, US events
|
|
81
|
+
qgist events today --symbol XAUUSD # Today, Gold-affecting events
|
|
82
|
+
qgist events today --json # Raw JSON output
|
|
83
|
+
|
|
84
|
+
# Example output:
|
|
85
|
+
# ┌──────────────┬────────┬─────────┬──────────────────────────────┬──────────┬──────────┬────────┐
|
|
86
|
+
# │ Time (UTC) │ Impact │ Country │ Event │ Forecast │ Previous │ Actual │
|
|
87
|
+
# ├──────────────┼────────┼─────────┼──────────────────────────────┼──────────┼──────────┼────────┤
|
|
88
|
+
# │ 08:30 │ HIGH │ US │ Non-Farm Payrolls │ 185K │ 175K │ — │
|
|
89
|
+
# │ 10:00 │ HIGH │ US │ ISM Manufacturing PMI │ 48.5 │ 47.8 │ — │
|
|
90
|
+
# └──────────────┴────────┴─────────┴──────────────────────────────┴──────────┴──────────┘
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
### `qgist config set|get|show`
|
|
96
|
+
|
|
97
|
+
Manage your API key and settings stored at `~/.config/qgist/config.toml`.
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
Usage: qgist config set KEY VALUE
|
|
101
|
+
qgist config get KEY
|
|
102
|
+
qgist config show
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Examples:**
|
|
106
|
+
```bash
|
|
107
|
+
qgist config set api-key qg_live_abc123
|
|
108
|
+
qgist config get api-key
|
|
109
|
+
# api-key = qg_live_abc*****
|
|
110
|
+
|
|
111
|
+
qgist config show
|
|
112
|
+
# ╭── QuantGist Config ──────────────────╮
|
|
113
|
+
# │ api-key = qg_live_abc***** │
|
|
114
|
+
# │ base-url = https://api.quantgist.com │
|
|
115
|
+
# ╰──────────────────────────────────────╯
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Config file location: `~/.config/qgist/config.toml`
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
### `qgist export <keyword>`
|
|
123
|
+
|
|
124
|
+
Export historical events matching a keyword to CSV or JSON.
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
Usage: qgist export KEYWORD [OPTIONS]
|
|
128
|
+
|
|
129
|
+
Arguments:
|
|
130
|
+
KEYWORD Keyword to search (e.g. nfp, cpi, fomc)
|
|
131
|
+
|
|
132
|
+
Options:
|
|
133
|
+
--from TEXT Start date (YYYY-MM-DD), default 30 days ago
|
|
134
|
+
--to TEXT End date (YYYY-MM-DD), default today
|
|
135
|
+
--format TEXT csv (default) | json
|
|
136
|
+
--output TEXT Output file path (default: stdout)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Examples:**
|
|
140
|
+
```bash
|
|
141
|
+
qgist export nfp # NFP events, last 30 days, CSV to stdout
|
|
142
|
+
qgist export cpi --from 2024-01-01 --to 2024-12-31 --format json
|
|
143
|
+
qgist export fomc --output fomc_history.csv
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
### `qgist status`
|
|
149
|
+
|
|
150
|
+
Check your connection and API key status.
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
qgist status
|
|
154
|
+
|
|
155
|
+
# ╭─ QuantGist Status ──────────────────────────────╮
|
|
156
|
+
# │ Connection ✓ Connected │
|
|
157
|
+
# │ API Key qg_live_abc***** (active) │
|
|
158
|
+
# │ Plan free │
|
|
159
|
+
# │ Rate limit 47 / 100 remaining today │
|
|
160
|
+
# ╰─────────────────────────────────────────────────╯
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Configuration
|
|
166
|
+
|
|
167
|
+
The CLI stores settings in `~/.config/qgist/config.toml`:
|
|
168
|
+
|
|
169
|
+
```toml
|
|
170
|
+
api-key = "qg_live_..."
|
|
171
|
+
base-url = "https://api.quantgist.com/v1"
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Environment variable override** — set `QUANTGIST_API_KEY` to bypass the config file:
|
|
175
|
+
```bash
|
|
176
|
+
export QUANTGIST_API_KEY=qg_live_...
|
|
177
|
+
qgist events
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Free API key
|
|
183
|
+
|
|
184
|
+
[quantgist.com/signup](https://quantgist.com/signup) — 100 calls/day, 365-day history. No credit card.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## License
|
|
189
|
+
|
|
190
|
+
MIT
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# qgist
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/qgist-cli)
|
|
4
|
+
[](https://pypi.org/project/qgist-cli)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
Command-line interface for the [QuantGist](https://quantgist.com) macro event API. Check upcoming economic events, export historical data, and configure your key — all from the terminal.
|
|
8
|
+
|
|
9
|
+
The PyPI package is **`qgist-cli`**; it installs the **`qgist`** command.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install qgist-cli
|
|
17
|
+
# or (recommended — installs as an isolated tool)
|
|
18
|
+
uv tool install qgist-cli
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# 1. Set your API key (get one free at quantgist.com/signup)
|
|
27
|
+
qgist config set api-key qg_live_your_key_here
|
|
28
|
+
|
|
29
|
+
# 2. Check today's events
|
|
30
|
+
qgist events
|
|
31
|
+
|
|
32
|
+
# 3. Check this week's high-impact events
|
|
33
|
+
qgist events week --impact high
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Commands
|
|
39
|
+
|
|
40
|
+
### `qgist events [today|week]`
|
|
41
|
+
|
|
42
|
+
Show upcoming macro events in a formatted table.
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
Usage: qgist events [PERIOD] [OPTIONS]
|
|
46
|
+
|
|
47
|
+
Arguments:
|
|
48
|
+
PERIOD today (default) | week
|
|
49
|
+
|
|
50
|
+
Options:
|
|
51
|
+
-s, --symbol TEXT Filter by symbol (e.g. XAUUSD)
|
|
52
|
+
-c, --country TEXT ISO country code (e.g. us, eu, gb)
|
|
53
|
+
-i, --impact TEXT Impact filter: low | medium | high
|
|
54
|
+
--json Output raw JSON
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Examples:**
|
|
58
|
+
```bash
|
|
59
|
+
qgist events # Today, all impacts
|
|
60
|
+
qgist events week # Next 7 days
|
|
61
|
+
qgist events week --impact high # This week, high-impact only
|
|
62
|
+
qgist events today --country us # Today, US events
|
|
63
|
+
qgist events today --symbol XAUUSD # Today, Gold-affecting events
|
|
64
|
+
qgist events today --json # Raw JSON output
|
|
65
|
+
|
|
66
|
+
# Example output:
|
|
67
|
+
# ┌──────────────┬────────┬─────────┬──────────────────────────────┬──────────┬──────────┬────────┐
|
|
68
|
+
# │ Time (UTC) │ Impact │ Country │ Event │ Forecast │ Previous │ Actual │
|
|
69
|
+
# ├──────────────┼────────┼─────────┼──────────────────────────────┼──────────┼──────────┼────────┤
|
|
70
|
+
# │ 08:30 │ HIGH │ US │ Non-Farm Payrolls │ 185K │ 175K │ — │
|
|
71
|
+
# │ 10:00 │ HIGH │ US │ ISM Manufacturing PMI │ 48.5 │ 47.8 │ — │
|
|
72
|
+
# └──────────────┴────────┴─────────┴──────────────────────────────┴──────────┴──────────┘
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### `qgist config set|get|show`
|
|
78
|
+
|
|
79
|
+
Manage your API key and settings stored at `~/.config/qgist/config.toml`.
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
Usage: qgist config set KEY VALUE
|
|
83
|
+
qgist config get KEY
|
|
84
|
+
qgist config show
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Examples:**
|
|
88
|
+
```bash
|
|
89
|
+
qgist config set api-key qg_live_abc123
|
|
90
|
+
qgist config get api-key
|
|
91
|
+
# api-key = qg_live_abc*****
|
|
92
|
+
|
|
93
|
+
qgist config show
|
|
94
|
+
# ╭── QuantGist Config ──────────────────╮
|
|
95
|
+
# │ api-key = qg_live_abc***** │
|
|
96
|
+
# │ base-url = https://api.quantgist.com │
|
|
97
|
+
# ╰──────────────────────────────────────╯
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Config file location: `~/.config/qgist/config.toml`
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
### `qgist export <keyword>`
|
|
105
|
+
|
|
106
|
+
Export historical events matching a keyword to CSV or JSON.
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
Usage: qgist export KEYWORD [OPTIONS]
|
|
110
|
+
|
|
111
|
+
Arguments:
|
|
112
|
+
KEYWORD Keyword to search (e.g. nfp, cpi, fomc)
|
|
113
|
+
|
|
114
|
+
Options:
|
|
115
|
+
--from TEXT Start date (YYYY-MM-DD), default 30 days ago
|
|
116
|
+
--to TEXT End date (YYYY-MM-DD), default today
|
|
117
|
+
--format TEXT csv (default) | json
|
|
118
|
+
--output TEXT Output file path (default: stdout)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Examples:**
|
|
122
|
+
```bash
|
|
123
|
+
qgist export nfp # NFP events, last 30 days, CSV to stdout
|
|
124
|
+
qgist export cpi --from 2024-01-01 --to 2024-12-31 --format json
|
|
125
|
+
qgist export fomc --output fomc_history.csv
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
### `qgist status`
|
|
131
|
+
|
|
132
|
+
Check your connection and API key status.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
qgist status
|
|
136
|
+
|
|
137
|
+
# ╭─ QuantGist Status ──────────────────────────────╮
|
|
138
|
+
# │ Connection ✓ Connected │
|
|
139
|
+
# │ API Key qg_live_abc***** (active) │
|
|
140
|
+
# │ Plan free │
|
|
141
|
+
# │ Rate limit 47 / 100 remaining today │
|
|
142
|
+
# ╰─────────────────────────────────────────────────╯
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Configuration
|
|
148
|
+
|
|
149
|
+
The CLI stores settings in `~/.config/qgist/config.toml`:
|
|
150
|
+
|
|
151
|
+
```toml
|
|
152
|
+
api-key = "qg_live_..."
|
|
153
|
+
base-url = "https://api.quantgist.com/v1"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Environment variable override** — set `QUANTGIST_API_KEY` to bypass the config file:
|
|
157
|
+
```bash
|
|
158
|
+
export QUANTGIST_API_KEY=qg_live_...
|
|
159
|
+
qgist events
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Free API key
|
|
165
|
+
|
|
166
|
+
[quantgist.com/signup](https://quantgist.com/signup) — 100 calls/day, 365-day history. No credit card.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
MIT
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "qgist-cli"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "CLI for the QuantGist macro event API — qgist events today"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
authors = [{ name = "QuantGist", email = "dev@quantgist.com" }]
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
keywords = ["quantgist", "trading", "macro", "cli", "economic-calendar", "earnings"]
|
|
14
|
+
dependencies = [
|
|
15
|
+
"quantgist>=0.7.1",
|
|
16
|
+
"typer>=0.12.0",
|
|
17
|
+
"rich>=13.0.0",
|
|
18
|
+
"tomli-w>=1.0.0",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[project.scripts]
|
|
22
|
+
qgist = "qgist.cli:main"
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Homepage = "https://quantgist.com"
|
|
26
|
+
Repository = "https://github.com/QuantGist-Technologies/quantgist-cli"
|
|
27
|
+
Documentation = "https://quantgist.com/docs"
|
|
28
|
+
|
|
29
|
+
[tool.hatch.build.targets.wheel]
|
|
30
|
+
packages = ["src/qgist"]
|
|
31
|
+
|
|
32
|
+
[tool.ruff]
|
|
33
|
+
line-length = 88
|
|
34
|
+
target-version = "py310"
|
|
File without changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from functools import lru_cache
|
|
3
|
+
|
|
4
|
+
from quantgist import QuantGistClient
|
|
5
|
+
|
|
6
|
+
from qgist.config_store import load_config
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@lru_cache(maxsize=1)
|
|
10
|
+
def get_client() -> QuantGistClient:
|
|
11
|
+
cfg = load_config()
|
|
12
|
+
api_key = os.environ.get("QUANTGIST_API_KEY") or cfg.get("api_key", "")
|
|
13
|
+
if not api_key:
|
|
14
|
+
import typer
|
|
15
|
+
typer.echo(
|
|
16
|
+
"No API key found. Run: qgist config set api-key <your-key>\n"
|
|
17
|
+
"Or set QUANTGIST_API_KEY environment variable.",
|
|
18
|
+
err=True,
|
|
19
|
+
)
|
|
20
|
+
raise typer.Exit(1)
|
|
21
|
+
return QuantGistClient(api_key=api_key)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
app = typer.Typer(
|
|
4
|
+
name="qgist",
|
|
5
|
+
help="QuantGist CLI — macro event data in your terminal.",
|
|
6
|
+
add_completion=False,
|
|
7
|
+
rich_markup_mode="rich",
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
# Import commands so they register themselves on `app`
|
|
11
|
+
from qgist.commands import config, events, export, status # noqa: E402, F401
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main() -> None:
|
|
15
|
+
app()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
if __name__ == "__main__":
|
|
19
|
+
main()
|
|
File without changes
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""qgist config set <key> <value> | qgist config get <key> | qgist config show"""
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.table import Table
|
|
7
|
+
|
|
8
|
+
from qgist.cli import app
|
|
9
|
+
from qgist.config_store import get_value, load_config, set_value
|
|
10
|
+
|
|
11
|
+
console = Console()
|
|
12
|
+
|
|
13
|
+
config_app = typer.Typer(help="Manage qgist configuration.")
|
|
14
|
+
app.add_typer(config_app, name="config")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@config_app.command("set")
|
|
18
|
+
def config_set(
|
|
19
|
+
key: str = typer.Argument(..., help="Config key (e.g. api-key, timezone)"),
|
|
20
|
+
value: str = typer.Argument(..., help="Value to set"),
|
|
21
|
+
) -> None:
|
|
22
|
+
"""Set a config value."""
|
|
23
|
+
set_value(key, value)
|
|
24
|
+
console.print(f"[green]✓[/] Set [bold]{key}[/] = {value!r}")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@config_app.command("get")
|
|
28
|
+
def config_get(
|
|
29
|
+
key: str = typer.Argument(..., help="Config key to retrieve"),
|
|
30
|
+
) -> None:
|
|
31
|
+
"""Get a single config value."""
|
|
32
|
+
val = get_value(key)
|
|
33
|
+
if val is None:
|
|
34
|
+
console.print(f"[yellow]Not set:[/] {key}")
|
|
35
|
+
raise typer.Exit(1)
|
|
36
|
+
console.print(val)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@config_app.command("show")
|
|
40
|
+
def config_show() -> None:
|
|
41
|
+
"""Show all current config values."""
|
|
42
|
+
cfg = load_config()
|
|
43
|
+
if not cfg:
|
|
44
|
+
console.print("[dim]No config found. Run: qgist config set api-key <your-key>[/]")
|
|
45
|
+
return
|
|
46
|
+
table = Table(title="qgist config", show_header=True)
|
|
47
|
+
table.add_column("Key", style="cyan")
|
|
48
|
+
table.add_column("Value")
|
|
49
|
+
for k, v in cfg.items():
|
|
50
|
+
display = "****" + str(v)[-4:] if "key" in k else str(v)
|
|
51
|
+
table.add_row(k, display)
|
|
52
|
+
console.print(table)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""qgist events [today|week] [--symbol] [--country] [--impact] [--json]"""
|
|
2
|
+
import json
|
|
3
|
+
from datetime import date, timedelta
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
from rich.table import Table
|
|
9
|
+
|
|
10
|
+
from qgist.cli import app
|
|
11
|
+
from qgist.api import get_client
|
|
12
|
+
|
|
13
|
+
console = Console()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@app.command("events")
|
|
17
|
+
def events_cmd(
|
|
18
|
+
period: str = typer.Argument("today", help="today | week"),
|
|
19
|
+
symbol: Optional[str] = typer.Option(None, "--symbol", "-s", help="Filter by symbol, e.g. XAUUSD"),
|
|
20
|
+
country: Optional[str] = typer.Option(None, "--country", "-c", help="ISO country code, e.g. us"),
|
|
21
|
+
impact: Optional[str] = typer.Option(None, "--impact", "-i", help="low | medium | high"),
|
|
22
|
+
as_json: bool = typer.Option(False, "--json", help="Output raw JSON"),
|
|
23
|
+
) -> None:
|
|
24
|
+
today = date.today()
|
|
25
|
+
from_date = str(today)
|
|
26
|
+
to_date = str(today if period == "today" else today + timedelta(days=6))
|
|
27
|
+
|
|
28
|
+
client = get_client()
|
|
29
|
+
response = client.get_events(
|
|
30
|
+
from_date=from_date,
|
|
31
|
+
to_date=to_date,
|
|
32
|
+
symbol=symbol,
|
|
33
|
+
country=country,
|
|
34
|
+
impact=impact, # type: ignore[arg-type]
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
if as_json:
|
|
38
|
+
typer.echo(json.dumps([e.model_dump() for e in response.data], default=str))
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
table = Table(title=f"Events — {period}", show_lines=False)
|
|
42
|
+
table.add_column("Time (UTC)", style="cyan", no_wrap=True)
|
|
43
|
+
table.add_column("Impact", justify="center")
|
|
44
|
+
table.add_column("Country", style="dim")
|
|
45
|
+
table.add_column("Event")
|
|
46
|
+
table.add_column("Forecast", justify="right", style="dim")
|
|
47
|
+
table.add_column("Previous", justify="right", style="dim")
|
|
48
|
+
table.add_column("Actual", justify="right")
|
|
49
|
+
|
|
50
|
+
impact_colors = {"high": "[red]", "medium": "[yellow]", "low": "[green]"}
|
|
51
|
+
|
|
52
|
+
for event in response.data:
|
|
53
|
+
color = impact_colors.get(event.impact, "")
|
|
54
|
+
table.add_row(
|
|
55
|
+
event.release_time.strftime("%H:%M"),
|
|
56
|
+
f"{color}{(event.impact or '').upper()}[/]",
|
|
57
|
+
(event.country or "").upper(),
|
|
58
|
+
event.title,
|
|
59
|
+
str(event.forecast) if event.forecast is not None else "—",
|
|
60
|
+
str(event.previous) if event.previous is not None else "—",
|
|
61
|
+
str(event.actual) if event.actual is not None else "—",
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
console.print(table)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""qgist export <event-name> --from <date> --to <date> [--format csv|json]"""
|
|
2
|
+
import csv
|
|
3
|
+
import io
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
from datetime import date
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
|
|
12
|
+
from qgist.cli import app
|
|
13
|
+
from qgist.api import get_client
|
|
14
|
+
|
|
15
|
+
console = Console()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@app.command("export")
|
|
19
|
+
def export_cmd(
|
|
20
|
+
event_name: str = typer.Argument(..., help="Event keyword to filter (e.g. nfp, cpi)"),
|
|
21
|
+
from_date: Optional[str] = typer.Option(None, "--from", help="Start date YYYY-MM-DD"),
|
|
22
|
+
to_date: Optional[str] = typer.Option(None, "--to", help="End date YYYY-MM-DD"),
|
|
23
|
+
fmt: str = typer.Option("csv", "--format", "-f", help="Output format: csv | json"),
|
|
24
|
+
output: Optional[str] = typer.Option(None, "--output", "-o", help="Output file path (default: stdout)"),
|
|
25
|
+
) -> None:
|
|
26
|
+
"""Export historical event data to CSV or JSON."""
|
|
27
|
+
client = get_client()
|
|
28
|
+
|
|
29
|
+
# The API caps per_page at 100; pagination is not yet implemented in v0.1.
|
|
30
|
+
response = client.get_events(
|
|
31
|
+
from_date=from_date or "2020-01-01",
|
|
32
|
+
to_date=to_date or str(date.today()),
|
|
33
|
+
limit=100,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# filter by keyword in title
|
|
37
|
+
keyword = event_name.lower()
|
|
38
|
+
filtered = [e for e in response.data if keyword in e.title.lower()]
|
|
39
|
+
|
|
40
|
+
if not filtered:
|
|
41
|
+
Console(stderr=True).print(f"[yellow]No events found matching '{event_name}'[/]")
|
|
42
|
+
raise typer.Exit(1)
|
|
43
|
+
|
|
44
|
+
out = sys.stdout if not output else open(output, "w", newline="")
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
if fmt == "json":
|
|
48
|
+
json.dump([e.model_dump() for e in filtered], out, default=str, indent=2)
|
|
49
|
+
if output:
|
|
50
|
+
console.print(f"[green]✓[/] Exported {len(filtered)} events to {output}")
|
|
51
|
+
else:
|
|
52
|
+
writer = csv.DictWriter(
|
|
53
|
+
out,
|
|
54
|
+
fieldnames=[
|
|
55
|
+
"id", "release_time", "title", "country", "currency",
|
|
56
|
+
"impact", "forecast", "previous", "actual", "surprise_score",
|
|
57
|
+
"symbols", "event_type", "source",
|
|
58
|
+
],
|
|
59
|
+
extrasaction="ignore", # model has more fields than we export
|
|
60
|
+
)
|
|
61
|
+
writer.writeheader()
|
|
62
|
+
for e in filtered:
|
|
63
|
+
row = e.model_dump()
|
|
64
|
+
row["symbols"] = ",".join(row.get("symbols") or [])
|
|
65
|
+
writer.writerow(row)
|
|
66
|
+
if output:
|
|
67
|
+
console.print(f"[green]✓[/] Exported {len(filtered)} events to {output}")
|
|
68
|
+
finally:
|
|
69
|
+
if output:
|
|
70
|
+
out.close()
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""qgist status — show API health, rate limit, and plan info"""
|
|
2
|
+
import typer
|
|
3
|
+
from rich.console import Console
|
|
4
|
+
from rich.panel import Panel
|
|
5
|
+
from rich.table import Table
|
|
6
|
+
|
|
7
|
+
from qgist.cli import app
|
|
8
|
+
from qgist.api import get_client
|
|
9
|
+
from qgist.config_store import get_value
|
|
10
|
+
|
|
11
|
+
console = Console()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@app.command("status")
|
|
15
|
+
def status_cmd() -> None:
|
|
16
|
+
"""Show API connection status, rate limit, and plan."""
|
|
17
|
+
client = get_client()
|
|
18
|
+
|
|
19
|
+
console.print("[dim]Checking QuantGist API...[/]")
|
|
20
|
+
try:
|
|
21
|
+
resp = client.get_events(limit=1)
|
|
22
|
+
except Exception as e:
|
|
23
|
+
console.print(f"[red]✗ API error:[/] {e}")
|
|
24
|
+
raise typer.Exit(1)
|
|
25
|
+
|
|
26
|
+
table = Table(show_header=False, box=None, padding=(0, 2))
|
|
27
|
+
table.add_column("Key", style="dim")
|
|
28
|
+
table.add_column("Value", style="bold")
|
|
29
|
+
|
|
30
|
+
table.add_row("Status", "[green]✓ Connected[/]")
|
|
31
|
+
|
|
32
|
+
remaining = resp.meta.rate_limit_remaining
|
|
33
|
+
if remaining is not None:
|
|
34
|
+
color = "green" if remaining > 10 else "yellow" if remaining > 0 else "red"
|
|
35
|
+
table.add_row("Rate limit remaining", f"[{color}]{remaining}[/]")
|
|
36
|
+
|
|
37
|
+
api_key = get_value("api_key") or ""
|
|
38
|
+
if api_key:
|
|
39
|
+
masked = api_key[:12] + "****"
|
|
40
|
+
table.add_row("API key", masked)
|
|
41
|
+
|
|
42
|
+
table.add_row("API base", "https://api.quantgist.com/v1")
|
|
43
|
+
|
|
44
|
+
console.print(Panel(table, title="qgist status", border_style="cyan"))
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import tomllib
|
|
2
|
+
import tomli_w
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
_CONFIG_PATH = Path.home() / ".config" / "qgist" / "config.toml"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def load_config() -> dict:
|
|
9
|
+
if not _CONFIG_PATH.exists():
|
|
10
|
+
return {}
|
|
11
|
+
with open(_CONFIG_PATH, "rb") as f:
|
|
12
|
+
return tomllib.load(f)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def save_config(config: dict) -> None:
|
|
16
|
+
_CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
17
|
+
with open(_CONFIG_PATH, "wb") as f:
|
|
18
|
+
tomli_w.dump(config, f)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def set_value(key: str, value: str) -> None:
|
|
22
|
+
cfg = load_config()
|
|
23
|
+
cfg[key.replace("-", "_")] = value
|
|
24
|
+
save_config(cfg)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_value(key: str) -> str | None:
|
|
28
|
+
return load_config().get(key.replace("-", "_"))
|