ticker-cli 1.0.0
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.
- package/CLAUDE.md +111 -0
- package/README.md +192 -0
- package/bun.lock +91 -0
- package/index.ts +40 -0
- package/package.json +24 -0
- package/src/commands/chart.ts +100 -0
- package/src/commands/index.ts +10 -0
- package/src/commands/indicator.ts +152 -0
- package/src/commands/insights.ts +42 -0
- package/src/commands/news.ts +46 -0
- package/src/commands/options.ts +69 -0
- package/src/commands/quote.ts +34 -0
- package/src/commands/recommendations.ts +42 -0
- package/src/commands/screener.ts +58 -0
- package/src/commands/search.ts +49 -0
- package/src/commands/summary.ts +50 -0
- package/src/services/index.ts +3 -0
- package/src/services/indicators.ts +188 -0
- package/src/services/yahoo.ts +205 -0
- package/src/types/index.ts +47 -0
- package/src/utils/date.ts +107 -0
- package/src/utils/index.ts +9 -0
- package/src/utils/output.ts +40 -0
- package/tsconfig.json +29 -0
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Use Bun instead of Node.js, npm, pnpm, or vite.
|
|
3
|
+
globs: "*.ts, *.tsx, *.html, *.css, *.js, *.jsx, package.json"
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Default to using Bun instead of Node.js.
|
|
8
|
+
|
|
9
|
+
- Use `bun <file>` instead of `node <file>` or `ts-node <file>`
|
|
10
|
+
- Use `bun test` instead of `jest` or `vitest`
|
|
11
|
+
- Use `bun build <file.html|file.ts|file.css>` instead of `webpack` or `esbuild`
|
|
12
|
+
- Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
|
|
13
|
+
- Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>` or `pnpm run <script>`
|
|
14
|
+
- Use `bunx <package> <command>` instead of `npx <package> <command>`
|
|
15
|
+
- Bun automatically loads .env, so don't use dotenv.
|
|
16
|
+
|
|
17
|
+
## APIs
|
|
18
|
+
|
|
19
|
+
- `Bun.serve()` supports WebSockets, HTTPS, and routes. Don't use `express`.
|
|
20
|
+
- `bun:sqlite` for SQLite. Don't use `better-sqlite3`.
|
|
21
|
+
- `Bun.redis` for Redis. Don't use `ioredis`.
|
|
22
|
+
- `Bun.sql` for Postgres. Don't use `pg` or `postgres.js`.
|
|
23
|
+
- `WebSocket` is built-in. Don't use `ws`.
|
|
24
|
+
- Prefer `Bun.file` over `node:fs`'s readFile/writeFile
|
|
25
|
+
- Bun.$`ls` instead of execa.
|
|
26
|
+
|
|
27
|
+
## Testing
|
|
28
|
+
|
|
29
|
+
Use `bun test` to run tests.
|
|
30
|
+
|
|
31
|
+
```ts#index.test.ts
|
|
32
|
+
import { test, expect } from "bun:test";
|
|
33
|
+
|
|
34
|
+
test("hello world", () => {
|
|
35
|
+
expect(1).toBe(1);
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Frontend
|
|
40
|
+
|
|
41
|
+
Use HTML imports with `Bun.serve()`. Don't use `vite`. HTML imports fully support React, CSS, Tailwind.
|
|
42
|
+
|
|
43
|
+
Server:
|
|
44
|
+
|
|
45
|
+
```ts#index.ts
|
|
46
|
+
import index from "./index.html"
|
|
47
|
+
|
|
48
|
+
Bun.serve({
|
|
49
|
+
routes: {
|
|
50
|
+
"/": index,
|
|
51
|
+
"/api/users/:id": {
|
|
52
|
+
GET: (req) => {
|
|
53
|
+
return new Response(JSON.stringify({ id: req.params.id }));
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
// optional websocket support
|
|
58
|
+
websocket: {
|
|
59
|
+
open: (ws) => {
|
|
60
|
+
ws.send("Hello, world!");
|
|
61
|
+
},
|
|
62
|
+
message: (ws, message) => {
|
|
63
|
+
ws.send(message);
|
|
64
|
+
},
|
|
65
|
+
close: (ws) => {
|
|
66
|
+
// handle close
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
development: {
|
|
70
|
+
hmr: true,
|
|
71
|
+
console: true,
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
HTML files can import .tsx, .jsx or .js files directly and Bun's bundler will transpile & bundle automatically. `<link>` tags can point to stylesheets and Bun's CSS bundler will bundle.
|
|
77
|
+
|
|
78
|
+
```html#index.html
|
|
79
|
+
<html>
|
|
80
|
+
<body>
|
|
81
|
+
<h1>Hello, world!</h1>
|
|
82
|
+
<script type="module" src="./frontend.tsx"></script>
|
|
83
|
+
</body>
|
|
84
|
+
</html>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
With the following `frontend.tsx`:
|
|
88
|
+
|
|
89
|
+
```tsx#frontend.tsx
|
|
90
|
+
import React from "react";
|
|
91
|
+
import { createRoot } from "react-dom/client";
|
|
92
|
+
|
|
93
|
+
// import .css files directly and it works
|
|
94
|
+
import './index.css';
|
|
95
|
+
|
|
96
|
+
const root = createRoot(document.body);
|
|
97
|
+
|
|
98
|
+
export default function Frontend() {
|
|
99
|
+
return <h1>Hello, world!</h1>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
root.render(<Frontend />);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Then, run index.ts
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
bun --hot ./index.ts
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
For more information, read the Bun API docs in `node_modules/bun-types/docs/**.mdx`.
|
package/README.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# ticker-cli
|
|
2
|
+
|
|
3
|
+
A powerful command-line interface for trading analysis that provides stock quotes, charts, technical indicators, news, and more.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun install
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bun run index.ts <command> [options]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or create an alias:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
alias ticker="bun run /path/to/ticker-cli/index.ts"
|
|
21
|
+
ticker quote AAPL
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Commands
|
|
25
|
+
|
|
26
|
+
### quote - Get stock quotes
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
ticker quote <symbols...>
|
|
30
|
+
|
|
31
|
+
# Examples:
|
|
32
|
+
ticker quote AAPL # Single quote
|
|
33
|
+
ticker quote AAPL MSFT GOOGL # Multiple quotes
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### chart - Get chart/historical data
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
ticker chart <symbol> [options]
|
|
40
|
+
|
|
41
|
+
Options:
|
|
42
|
+
-p, --period <period> Preset period: 1d, 5d, 1wk, 1mo, 3mo, 6mo, 1y, 2y, 5y
|
|
43
|
+
-s, --start <date> Start date (YYYY-MM-DD)
|
|
44
|
+
-e, --end <date> End date (YYYY-MM-DD)
|
|
45
|
+
-i, --interval <interval> Interval: 1m, 5m, 15m, 30m, 1h, 1d, 1wk, 1mo
|
|
46
|
+
|
|
47
|
+
# Examples:
|
|
48
|
+
ticker chart AAPL -p 1mo
|
|
49
|
+
ticker chart AAPL --start 2025-01-01 --end 2025-12-31
|
|
50
|
+
ticker chart AAPL -p 1y --interval 1wk
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### indicator - Calculate technical indicators
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
ticker indicator <symbol> <indicator> [options]
|
|
57
|
+
|
|
58
|
+
Indicators:
|
|
59
|
+
sma Simple Moving Average
|
|
60
|
+
ema Exponential Moving Average
|
|
61
|
+
rsi Relative Strength Index
|
|
62
|
+
macd Moving Average Convergence Divergence
|
|
63
|
+
bb Bollinger Bands
|
|
64
|
+
|
|
65
|
+
Options:
|
|
66
|
+
-p, --period <period> Period for historical data
|
|
67
|
+
-s, --start <date> Start date
|
|
68
|
+
-e, --end <date> End date
|
|
69
|
+
--length <number> Period length (default: 20 for SMA/EMA/BB, 14 for RSI)
|
|
70
|
+
--short <number> Short period for MACD (default: 12)
|
|
71
|
+
--long <number> Long period for MACD (default: 26)
|
|
72
|
+
--signal <number> Signal period for MACD (default: 9)
|
|
73
|
+
|
|
74
|
+
# Examples:
|
|
75
|
+
ticker indicator AAPL sma -p 3mo
|
|
76
|
+
ticker indicator AAPL ema --length 50 -p 6mo
|
|
77
|
+
ticker indicator AAPL rsi -p 3mo
|
|
78
|
+
ticker indicator AAPL macd -p 6mo
|
|
79
|
+
ticker indicator AAPL bb -p 3mo
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### search - Search for symbols
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
ticker search <query>
|
|
86
|
+
|
|
87
|
+
# Examples:
|
|
88
|
+
ticker search apple
|
|
89
|
+
ticker search "micro soft"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### summary - Get quote summary
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
ticker summary <symbol> [options]
|
|
96
|
+
|
|
97
|
+
Options:
|
|
98
|
+
-m, --modules <modules> Comma-separated modules
|
|
99
|
+
|
|
100
|
+
# Examples:
|
|
101
|
+
ticker summary AAPL
|
|
102
|
+
ticker summary AAPL -m summaryProfile,summaryDetail
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### news - Get stock news
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
ticker news <symbol> [options]
|
|
109
|
+
|
|
110
|
+
Options:
|
|
111
|
+
-l, --limit <number> Number of articles (default: 10)
|
|
112
|
+
|
|
113
|
+
# Examples:
|
|
114
|
+
ticker news AAPL
|
|
115
|
+
ticker news AAPL --limit 20
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### insights - Get stock insights
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
ticker insights <symbol>
|
|
122
|
+
|
|
123
|
+
# Examples:
|
|
124
|
+
ticker insights AAPL
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### options - Get options chain
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
ticker options <symbol> [options]
|
|
131
|
+
|
|
132
|
+
Options:
|
|
133
|
+
-d, --date <date> Expiration date (YYYY-MM-DD)
|
|
134
|
+
--calls Show only calls
|
|
135
|
+
--puts Show only puts
|
|
136
|
+
|
|
137
|
+
# Examples:
|
|
138
|
+
ticker options AAPL
|
|
139
|
+
ticker options AAPL -d 2026-03-21
|
|
140
|
+
ticker options AAPL --calls
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### recommendations - Get analyst recommendations
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
ticker recommendations <symbol>
|
|
147
|
+
|
|
148
|
+
# Examples:
|
|
149
|
+
ticker recommendations AAPL
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### screener - Screen stocks
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
ticker screener [options]
|
|
156
|
+
|
|
157
|
+
Options:
|
|
158
|
+
-q, --query <query> Predefined query (default: most_actives)
|
|
159
|
+
|
|
160
|
+
Available Queries:
|
|
161
|
+
most_actives, day_gainers, day_losers,
|
|
162
|
+
undervalued_growth_stocks, undervalued_large_caps,
|
|
163
|
+
growth_technology_stocks, top_mutual_funds
|
|
164
|
+
|
|
165
|
+
# Examples:
|
|
166
|
+
ticker screener
|
|
167
|
+
ticker screener -q day_gainers
|
|
168
|
+
ticker screener -q undervalued_large_caps
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Global Options
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
--pretty Pretty print JSON output (default: true)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Output Format
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
ticker quote AAPL
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Dependencies
|
|
184
|
+
|
|
185
|
+
- [commander.js](https://github.com/tj/commander.js) - CLI framework
|
|
186
|
+
- [yahoo-finance2](https://github.com/gadicc/yahoo-finance2) - Yahoo Finance API
|
|
187
|
+
- [indicatorts](https://github.com/cinar/indicatorts) - Technical indicators
|
|
188
|
+
- [Bun](https://bun.sh) - JavaScript runtime
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
MIT
|
package/bun.lock
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"configVersion": 1,
|
|
4
|
+
"workspaces": {
|
|
5
|
+
"": {
|
|
6
|
+
"name": "ticker-cli",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"commander": "^14.0.3",
|
|
9
|
+
"indicatorts": "^2.2.2",
|
|
10
|
+
"yahoo-finance2": "^3.13.0",
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@types/bun": "latest",
|
|
14
|
+
},
|
|
15
|
+
"peerDependencies": {
|
|
16
|
+
"typescript": "^5",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
"packages": {
|
|
21
|
+
"@deno/shim-deno": ["@deno/shim-deno@0.18.2", "", { "dependencies": { "@deno/shim-deno-test": "^0.5.0", "which": "^4.0.0" } }, "sha512-oQ0CVmOio63wlhwQF75zA4ioolPvOwAoK0yuzcS5bDC1JUvH3y1GS8xPh8EOpcoDQRU4FTG8OQfxhpR+c6DrzA=="],
|
|
22
|
+
|
|
23
|
+
"@deno/shim-deno-test": ["@deno/shim-deno-test@0.5.0", "", {}, "sha512-4nMhecpGlPi0cSzT67L+Tm+GOJqvuk8gqHBziqcUQOarnuIax1z96/gJHCSIz2Z0zhxE6Rzwb3IZXPtFh51j+w=="],
|
|
24
|
+
|
|
25
|
+
"@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="],
|
|
26
|
+
|
|
27
|
+
"@types/node": ["@types/node@25.2.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ=="],
|
|
28
|
+
|
|
29
|
+
"bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="],
|
|
30
|
+
|
|
31
|
+
"commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="],
|
|
32
|
+
|
|
33
|
+
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
|
34
|
+
|
|
35
|
+
"escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
|
|
36
|
+
|
|
37
|
+
"fetch-mock-cache": ["fetch-mock-cache@2.3.1", "", { "dependencies": { "debug": "^4.3.4", "filenamify-url": "2.1.2" } }, "sha512-hDk+Nbt0Y8Aq7KTEU6ASQAcpB34UjhkpD3QjzD6yvEKP4xVElAqXrjQ7maL+LYMGafx51Zq6qUfDM57PNu/qMw=="],
|
|
38
|
+
|
|
39
|
+
"filename-reserved-regex": ["filename-reserved-regex@2.0.0", "", {}, "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ=="],
|
|
40
|
+
|
|
41
|
+
"filenamify": ["filenamify@4.3.0", "", { "dependencies": { "filename-reserved-regex": "^2.0.0", "strip-outer": "^1.0.1", "trim-repeated": "^1.0.0" } }, "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg=="],
|
|
42
|
+
|
|
43
|
+
"filenamify-url": ["filenamify-url@2.1.2", "", { "dependencies": { "filenamify": "^4.3.0", "humanize-url": "^2.1.1" } }, "sha512-3rMbAr7vDNMOGsj1aMniQFl749QjgM+lMJ/77ZRSPTIgxvolZwoQbn8dXLs7xfd+hAdli+oTnSWZNkJJLWQFEQ=="],
|
|
44
|
+
|
|
45
|
+
"humanize-url": ["humanize-url@2.1.1", "", { "dependencies": { "normalize-url": "^4.5.1" } }, "sha512-V4nxsPGNE7mPjr1qDp471YfW8nhBiTRWrG/4usZlpvFU8I7gsV7Jvrrzv/snbLm5dWO3dr1ennu2YqnhTWFmYA=="],
|
|
46
|
+
|
|
47
|
+
"indicatorts": ["indicatorts@2.2.2", "", {}, "sha512-oJRe83n2zj826Mlp2RKQVfurqbq5dEHzAWgZidiYkS0mrx3GCbXlNj59YtwZvekRmNwi/d4NdeHGHd8Nspl6Xg=="],
|
|
48
|
+
|
|
49
|
+
"isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="],
|
|
50
|
+
|
|
51
|
+
"json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="],
|
|
52
|
+
|
|
53
|
+
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
|
54
|
+
|
|
55
|
+
"normalize-url": ["normalize-url@4.5.1", "", {}, "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA=="],
|
|
56
|
+
|
|
57
|
+
"psl": ["psl@1.15.0", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w=="],
|
|
58
|
+
|
|
59
|
+
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
|
60
|
+
|
|
61
|
+
"querystringify": ["querystringify@2.2.0", "", {}, "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="],
|
|
62
|
+
|
|
63
|
+
"requires-port": ["requires-port@1.0.0", "", {}, "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="],
|
|
64
|
+
|
|
65
|
+
"strip-outer": ["strip-outer@1.0.1", "", { "dependencies": { "escape-string-regexp": "^1.0.2" } }, "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg=="],
|
|
66
|
+
|
|
67
|
+
"tldts": ["tldts@6.1.86", "", { "dependencies": { "tldts-core": "^6.1.86" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ=="],
|
|
68
|
+
|
|
69
|
+
"tldts-core": ["tldts-core@6.1.86", "", {}, "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA=="],
|
|
70
|
+
|
|
71
|
+
"tough-cookie": ["tough-cookie@5.1.2", "", { "dependencies": { "tldts": "^6.1.32" } }, "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A=="],
|
|
72
|
+
|
|
73
|
+
"tough-cookie-file-store": ["tough-cookie-file-store@2.0.3", "", { "dependencies": { "tough-cookie": "^4.0.0" } }, "sha512-sMpZVcmFf6EYFHFFl+SYH4W1/OnXBYMGDsv2IlbQ2caHyFElW/UR/gpj/KYU1JwmP4dE9xqwv2+vWcmlXHojSw=="],
|
|
74
|
+
|
|
75
|
+
"trim-repeated": ["trim-repeated@1.0.0", "", { "dependencies": { "escape-string-regexp": "^1.0.2" } }, "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg=="],
|
|
76
|
+
|
|
77
|
+
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
|
78
|
+
|
|
79
|
+
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
|
80
|
+
|
|
81
|
+
"universalify": ["universalify@0.2.0", "", {}, "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg=="],
|
|
82
|
+
|
|
83
|
+
"url-parse": ["url-parse@1.5.10", "", { "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" } }, "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ=="],
|
|
84
|
+
|
|
85
|
+
"which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="],
|
|
86
|
+
|
|
87
|
+
"yahoo-finance2": ["yahoo-finance2@3.13.0", "", { "dependencies": { "@deno/shim-deno": "~0.18.0", "fetch-mock-cache": "npm:fetch-mock-cache@^2.1.3", "json-schema": "^0.4.0", "tough-cookie": "npm:tough-cookie@^5.1.1", "tough-cookie-file-store": "npm:tough-cookie-file-store@^2.0.3" }, "bin": { "yahoo-finance": "esm/bin/yahoo-finance.js" } }, "sha512-czBj2q/MD68YEsB7aXNnGhJvWxYZn01O5r/i7VYiQV2m2sWwhca6tKgjwf/LT7zHHEVxhKNiGLB46glLnmq9Ag=="],
|
|
88
|
+
|
|
89
|
+
"tough-cookie-file-store/tough-cookie": ["tough-cookie@4.1.4", "", { "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", "universalify": "^0.2.0", "url-parse": "^1.5.3" } }, "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag=="],
|
|
90
|
+
}
|
|
91
|
+
}
|
package/index.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import {
|
|
4
|
+
createQuoteCommand,
|
|
5
|
+
createChartCommand,
|
|
6
|
+
createSearchCommand,
|
|
7
|
+
createSummaryCommand,
|
|
8
|
+
createNewsCommand,
|
|
9
|
+
createInsightsCommand,
|
|
10
|
+
createOptionsCommand,
|
|
11
|
+
createRecommendationsCommand,
|
|
12
|
+
createScreenerCommand,
|
|
13
|
+
createIndicatorCommand,
|
|
14
|
+
} from "./src/commands";
|
|
15
|
+
|
|
16
|
+
const program = new Command();
|
|
17
|
+
|
|
18
|
+
program
|
|
19
|
+
.name("ticker")
|
|
20
|
+
.description(
|
|
21
|
+
"Trading analysis CLI - stock quotes, charts, indicators, and more",
|
|
22
|
+
)
|
|
23
|
+
.version("1.0.0")
|
|
24
|
+
.option("--table", "Output as table instead of JSON (global option)")
|
|
25
|
+
.option("--pretty", "Pretty print JSON output", true);
|
|
26
|
+
|
|
27
|
+
// Add all commands
|
|
28
|
+
program.addCommand(createQuoteCommand());
|
|
29
|
+
program.addCommand(createChartCommand());
|
|
30
|
+
program.addCommand(createSearchCommand());
|
|
31
|
+
program.addCommand(createSummaryCommand());
|
|
32
|
+
program.addCommand(createNewsCommand());
|
|
33
|
+
program.addCommand(createInsightsCommand());
|
|
34
|
+
program.addCommand(createOptionsCommand());
|
|
35
|
+
program.addCommand(createRecommendationsCommand());
|
|
36
|
+
program.addCommand(createScreenerCommand());
|
|
37
|
+
program.addCommand(createIndicatorCommand());
|
|
38
|
+
|
|
39
|
+
// Parse arguments and run
|
|
40
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ticker-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"module": "index.ts",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ticker": "./index.ts"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "bun run index.ts",
|
|
11
|
+
"ticker": "bun run index.ts"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@types/bun": "latest"
|
|
15
|
+
},
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"typescript": "^5"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"commander": "^14.0.3",
|
|
21
|
+
"indicatorts": "^2.2.2",
|
|
22
|
+
"yahoo-finance2": "^3.13.0"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { createYahooService } from "../services";
|
|
3
|
+
import { createFormatter, isValidPeriod, isValidInterval } from "../utils";
|
|
4
|
+
import type { PeriodPreset, IntervalType } from "../types";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Create the chart command
|
|
8
|
+
*/
|
|
9
|
+
export function createChartCommand(): Command {
|
|
10
|
+
const command = new Command("chart");
|
|
11
|
+
|
|
12
|
+
command
|
|
13
|
+
.description("Get chart/historical data for a symbol")
|
|
14
|
+
.argument("<symbol>", "Stock symbol (e.g., AAPL)")
|
|
15
|
+
.option(
|
|
16
|
+
"-p, --period <period>",
|
|
17
|
+
"Preset period: 1d, 5d, 1wk, 1mo, 3mo, 6mo, 1y, 2y, 5y",
|
|
18
|
+
)
|
|
19
|
+
.option("-s, --start <date>", "Start date (YYYY-MM-DD)")
|
|
20
|
+
.option("-e, --end <date>", "End date (YYYY-MM-DD)")
|
|
21
|
+
.option(
|
|
22
|
+
"-i, --interval <interval>",
|
|
23
|
+
"Interval: 1m, 5m, 15m, 30m, 1h, 1d, 1wk, 1mo",
|
|
24
|
+
)
|
|
25
|
+
.option("--table", "Output as table instead of JSON")
|
|
26
|
+
.option("--pretty", "Pretty print JSON output", true)
|
|
27
|
+
.action(
|
|
28
|
+
async (
|
|
29
|
+
symbol: string,
|
|
30
|
+
options: {
|
|
31
|
+
period?: string;
|
|
32
|
+
start?: string;
|
|
33
|
+
end?: string;
|
|
34
|
+
interval?: string;
|
|
35
|
+
table?: boolean;
|
|
36
|
+
pretty?: boolean;
|
|
37
|
+
},
|
|
38
|
+
) => {
|
|
39
|
+
const yahooService = createYahooService();
|
|
40
|
+
const formatter = createFormatter(options);
|
|
41
|
+
|
|
42
|
+
// Validate period if provided
|
|
43
|
+
let period: PeriodPreset | undefined;
|
|
44
|
+
if (options.period) {
|
|
45
|
+
if (!isValidPeriod(options.period)) {
|
|
46
|
+
console.error(
|
|
47
|
+
`Invalid period: ${options.period}. Valid options: 1d, 5d, 1wk, 1mo, 3mo, 6mo, 1y, 2y, 5y`,
|
|
48
|
+
);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
period = options.period as PeriodPreset;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Validate interval if provided
|
|
55
|
+
let interval: IntervalType | undefined;
|
|
56
|
+
if (options.interval) {
|
|
57
|
+
if (!isValidInterval(options.interval)) {
|
|
58
|
+
console.error(
|
|
59
|
+
`Invalid interval: ${options.interval}. Valid options: 1m, 5m, 15m, 30m, 1h, 1d, 1wk, 1mo`,
|
|
60
|
+
);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
interval = options.interval as IntervalType;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Validate date range
|
|
67
|
+
if (options.start && options.end) {
|
|
68
|
+
const startDate = new Date(options.start);
|
|
69
|
+
const endDate = new Date(options.end);
|
|
70
|
+
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
|
|
71
|
+
console.error("Invalid date format. Use YYYY-MM-DD");
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
if (startDate >= endDate) {
|
|
75
|
+
console.error("Start date must be before end date");
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const chartData = await yahooService.getChart(symbol, {
|
|
82
|
+
period,
|
|
83
|
+
start: options.start,
|
|
84
|
+
end: options.end,
|
|
85
|
+
interval,
|
|
86
|
+
});
|
|
87
|
+
const output = formatter.format(chartData);
|
|
88
|
+
console.log(output);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error(
|
|
91
|
+
"Error fetching chart data:",
|
|
92
|
+
error instanceof Error ? error.message : String(error),
|
|
93
|
+
);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
return command;
|
|
100
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { createQuoteCommand } from "./quote";
|
|
2
|
+
export { createChartCommand } from "./chart";
|
|
3
|
+
export { createSearchCommand } from "./search";
|
|
4
|
+
export { createSummaryCommand } from "./summary";
|
|
5
|
+
export { createNewsCommand } from "./news";
|
|
6
|
+
export { createInsightsCommand } from "./insights";
|
|
7
|
+
export { createOptionsCommand } from "./options";
|
|
8
|
+
export { createRecommendationsCommand } from "./recommendations";
|
|
9
|
+
export { createScreenerCommand } from "./screener";
|
|
10
|
+
export { createIndicatorCommand } from "./indicator";
|