@bloomai/cli 0.1.3 → 0.1.5

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/README.md CHANGED
@@ -34,27 +34,71 @@ jq '.data[] | select(.revenue_growth > 0.1)' /tmp/bloom/aapl-revenue.json
34
34
 
35
35
  ## Commands
36
36
 
37
+ ### Core Research
37
38
  | Command | What it does | Example |
38
39
  |---------|-------------|---------|
39
40
  | `info` | Company fundamentals, ratings, peers | `bloom info AAPL MSFT` |
40
41
  | `news` | Recent news headlines | `bloom news AAPL --limit 5` |
41
42
  | `price` | Historical price data | `bloom price AAPL --timeframes 1d,1m,1y` |
42
43
  | `financials` | Revenue, margins, cash flow | `bloom financials AAPL --type revenue` |
43
- | `sentiment` | Market mood (AAII, Fear&Greed, VIX) | `bloom sentiment` |
44
- | `market` | Market map, sectors, movers | `bloom market --type top_movers` |
45
- | `collections` | Curated stock lists by theme | `bloom collections --section VALUE` |
46
- | `screen` | Filter stocks by metrics | `bloom screen "market_cap > 100B" "pe_ratio < 25"` |
47
44
  | `earnings` | Earnings history & estimates | `bloom earnings AAPL` |
45
+ | `earnings-calendar` | Upcoming earnings dates | `bloom earnings-calendar --days 7` |
48
46
  | `technicals` | RSI, MAs, patterns, options flow | `bloom technicals AAPL` |
49
- | `options-history` | Options sentiment over time | `bloom options-history AAPL --days 30` |
47
+ | `ma` | Raw moving average data (SMA/EMA) | `bloom ma AAPL --sma 50,100,200 --ema 20` |
48
+ | `options-history` | Options sentiment evolution over time | `bloom options-history AAPL` |
49
+ | `transcript` | Search earnings call transcripts | `bloom transcript AAPL "AI" "services"` |
50
+ | `compare` | Side-by-side stock comparison | `bloom compare AAPL MSFT GOOG` |
51
+
52
+ ### Valuation & Risk
53
+ | Command | What it does | Example |
54
+ |---------|-------------|---------|
55
+ | `dcf` | Discounted cash flow valuation | `bloom dcf AAPL` |
56
+ | `risk` | Risk factors from SEC 10-K filings | `bloom risk AAPL` |
57
+ | `ratings` | Analyst grades & price targets | `bloom ratings AAPL` |
58
+ | `short-interest` | Short interest history | `bloom short-interest AAPL` |
59
+ | `holders` | Institutional & mutual fund holders | `bloom holders AAPL` |
60
+ | `insider` | SEC Form 4 insider trading | `bloom insider AAPL` |
61
+
62
+ ### Portfolio & Strategy
63
+ | Command | What it does | Example |
64
+ |---------|-------------|---------|
50
65
  | `portfolio` | Portfolio risk analysis | `bloom portfolio '{"AAPL":0.5,"MSFT":0.5}'` |
66
+ | `backtest` | Portfolio backtest against benchmark | `bloom backtest --symbols AAPL,MSFT --allocations 0.5,0.5` |
67
+ | `correlation` | Correlation matrix for symbols | `bloom correlation AAPL MSFT GOOG` |
68
+ | `drawdown` | Portfolio drawdown analysis | `bloom drawdown --symbols AAPL,MSFT --allocations 0.5,0.5` |
69
+ | `position-size` | Kelly criterion position sizing | `bloom position-size --bull 0.6 --bear -0.15 --conviction 8 --value 100000` |
51
70
  | `trades` | AI trade evaluation | `bloom trades "Buy AAPL: strong AI catalysts"` |
52
71
  | `catalysts` | Forward-looking value drivers | `bloom catalysts AAPL MSFT` |
53
- | `position-size` | Kelly criterion sizing | `bloom position-size --bull 0.6 --bear -0.15 --conviction 8 --value 100000` |
54
- | `transcript` | Search earnings call transcripts | `bloom transcript AAPL "AI" "services"` |
55
- | `ai-trades` | Recent AI model trade decisions (InvestingArena) | `bloom ai-trades --model claude --limit 5` |
72
+
73
+ ### Market & Macro
74
+ | Command | What it does | Example |
75
+ |---------|-------------|---------|
76
+ | `sentiment` | Market mood (AAII, Fear&Greed, VIX) | `bloom sentiment` |
77
+ | `market` | Market map, sectors, movers | `bloom market --type top_movers` |
78
+ | `macro` | GDP, CPI, unemployment, fed funds, treasury yields | `bloom macro --indicators GDP,CPI` |
79
+ | `sectors` | Sector performance across time periods | `bloom sectors` |
80
+ | `screen` | Filter stocks by metrics | `bloom screen "market_cap > 100B" "pe_ratio < 25"` |
81
+ | `collections` | Curated stock lists by theme | `bloom collections --section VALUE` |
82
+
83
+ ### Corporate Events
84
+ | Command | What it does | Example |
85
+ |---------|-------------|---------|
86
+ | `dividends` | Dividend history | `bloom dividends AAPL` |
87
+ | `splits` | Stock split history | `bloom splits AAPL` |
88
+ | `ipo` | Upcoming and recent IPOs | `bloom ipo --from 2026-05-01` |
89
+
90
+ ### AI Arena
91
+ | Command | What it does | Example |
92
+ |---------|-------------|---------|
93
+ | `ai-trades` | Recent AI model trade decisions | `bloom ai-trades --model claude --limit 5` |
56
94
  | `ai-portfolio` | AI model portfolio positions & performance | `bloom ai-portfolio --model openai` |
57
95
 
96
+ ## Environment Variables
97
+
98
+ | Variable | Required for | Description |
99
+ |----------|-------------|-------------|
100
+ | `BLOOM_API_KEY` | All commands | Bloom API key (`bloom auth login`) |
101
+
58
102
  ## Global Flags
59
103
 
60
104
  Every command supports:
@@ -117,6 +161,21 @@ bloom transcript AAPL "AI" "services" "margins" --max 20 -o /tmp/bloom/transcrip
117
161
  jq '.matches[] | {speaker, text}' /tmp/bloom/transcript.json
118
162
  ```
119
163
 
164
+ ### Moving Averages
165
+ ```bash
166
+ # Default: 100-day SMA + 100-day EMA
167
+ bloom ma AAPL
168
+
169
+ # Custom periods
170
+ bloom ma AAPL --sma 50,100,200 --ema 20,100
171
+
172
+ # Last 50 data points, save to file
173
+ bloom ma AAPL --sma 200 --limit 50 -o /tmp/bloom/aapl-ma.json
174
+
175
+ # Extract latest values
176
+ jq '.indicators | to_entries[] | {(.key): .value | to_entries | last | .value}' /tmp/bloom/aapl-ma.json
177
+ ```
178
+
120
179
  ### AI Arena (InvestingArena — 3 AIs with real money)
121
180
  ```bash
122
181
  # All AI models' recent trades
@@ -138,6 +197,41 @@ bloom ai-portfolio --model gemini
138
197
  jq '[.[] | {model: .ai_model, return_pct, account_value}]' /tmp/bloom/ai-portfolio.json
139
198
  ```
140
199
 
200
+ ### Valuation & Risk Research
201
+ ```bash
202
+ # DCF valuation
203
+ bloom dcf AAPL -o /tmp/bloom/aapl-dcf.json
204
+
205
+ # Risk factors from 10-K filing
206
+ bloom risk AAPL -o /tmp/bloom/aapl-risks.json
207
+
208
+ # Analyst ratings and price targets
209
+ bloom ratings AAPL
210
+
211
+ # Who owns this stock?
212
+ bloom holders AAPL --limit 10
213
+ bloom insider AAPL
214
+
215
+ # Short interest
216
+ bloom short-interest AAPL
217
+ ```
218
+
219
+ ### Portfolio Analytics
220
+ ```bash
221
+ # Backtest a portfolio
222
+ bloom backtest --symbols AAPL,MSFT,GOOG --allocations 0.4,0.3,0.3 -o /tmp/bloom/backtest.json
223
+
224
+ # Correlation matrix
225
+ bloom correlation AAPL MSFT GOOG AMZN
226
+
227
+ # Drawdown analysis
228
+ bloom drawdown --symbols AAPL,MSFT --allocations 0.5,0.5
229
+
230
+ # Macro overview
231
+ bloom macro --indicators GDP,CPI,UNEMPLOYMENT
232
+ bloom sectors
233
+ ```
234
+
141
235
  ## Tips
142
236
 
143
237
  - Use `-o` to download data to files, then `jq` to extract. Saves context tokens.
package/SKILL.md CHANGED
@@ -50,6 +50,16 @@ jq '.data[] | select(.revenue_growth > 0.1)' /tmp/bloom/aapl-revenue.json
50
50
  | `transcript` | Search earnings call transcripts | `bloom transcript AAPL "AI" "services"` |
51
51
  | `ai-trades` | Recent AI model trade decisions (InvestingArena) | `bloom ai-trades --model claude --limit 5` |
52
52
  | `ai-portfolio` | AI model portfolio positions & performance | `bloom ai-portfolio --model openai` |
53
+ | `search` | Web search via Serper (Google) | `bloom search "nvidia earnings Q1 2026"` |
54
+ | `scrape` | Scrape a web page via Firecrawl | `bloom scrape https://example.com` |
55
+
56
+ ## Environment Variables
57
+
58
+ | Variable | Required for | Description |
59
+ |----------|-------------|-------------|
60
+ | `BLOOM_API_KEY` | All financial commands | Bloom API key (`bloom auth login`) |
61
+ | `SERPER_API_KEY` | `bloom search` | Serper.dev API key for web search |
62
+ | `FIRECRAWL_API_KEY` | `bloom scrape` | Firecrawl API key for web scraping |
53
63
 
54
64
  ## Global Flags
55
65
 
package/dist/index.js CHANGED
@@ -110,7 +110,8 @@ function registerAuthCommand(program2) {
110
110
  }
111
111
 
112
112
  // src/api.ts
113
- var MCP_URL = "https://api.getbloom.app/mcp/";
113
+ var API_BASE = "https://api.getbloom.app";
114
+ var MCP_URL = `${API_BASE}/mcp/`;
114
115
  var requestId = 0;
115
116
  async function callTool(toolName, args) {
116
117
  const apiKey = requireApiKey();
@@ -150,6 +151,27 @@ async function callTool(toolName, args) {
150
151
  return text;
151
152
  }
152
153
  }
154
+ async function callRest(path2, params) {
155
+ const apiKey = requireApiKey();
156
+ const url = new URL(path2, API_BASE);
157
+ if (params) {
158
+ for (const [k, v] of Object.entries(params)) {
159
+ url.searchParams.set(k, v);
160
+ }
161
+ }
162
+ const res = await fetch(url.toString(), {
163
+ method: "GET",
164
+ headers: {
165
+ Authorization: `Bearer ${apiKey}`,
166
+ "Content-Type": "application/json"
167
+ }
168
+ });
169
+ if (!res.ok) {
170
+ const text = await res.text().catch(() => "");
171
+ throw new Error(`API error ${res.status}: ${text || res.statusText}`);
172
+ }
173
+ return res.json();
174
+ }
153
175
 
154
176
  // src/format.ts
155
177
  import Table from "cli-table3";
@@ -165,12 +187,12 @@ function outputResult(data, opts, tableFormatter) {
165
187
  emit(JSON.stringify(data, null, 2), opts);
166
188
  return;
167
189
  }
168
- const fmt = resolveFormat(opts);
169
- if (fmt === "json") {
190
+ const fmt2 = resolveFormat(opts);
191
+ if (fmt2 === "json") {
170
192
  emit(JSON.stringify(data, null, 2), opts);
171
193
  return;
172
194
  }
173
- if (fmt === "csv") {
195
+ if (fmt2 === "csv") {
174
196
  emit(toCSV(data), opts);
175
197
  return;
176
198
  }
@@ -452,7 +474,9 @@ var CHART_TYPES = [
452
474
  "net_earnings",
453
475
  "net_earnings_growth",
454
476
  "free_cash_flow",
455
- "free_cash_flow_growth"
477
+ "free_cash_flow_growth",
478
+ "stock_based_compensation",
479
+ "stock_based_compensation_growth"
456
480
  ];
457
481
  function registerFinancialsCommand(program2) {
458
482
  addGlobalOptions(
@@ -511,12 +535,13 @@ function formatSentiment(data) {
511
535
  // src/commands/market.ts
512
536
  function registerMarketCommand(program2) {
513
537
  addGlobalOptions(
514
- program2.command("market").description("Market performance, sectors, global").option("--type <type>", "top_movers|sector_breakdown|global_markets|major_indexes", "top_movers").option("--period <p>", "1d|1w|1m|3m|6m|ytd|1y|5y", "1d").option("--limit <n>", "Max stocks for top_movers", "24")
538
+ program2.command("market").description("Market performance, sectors, global").option("--type <type>", "top_movers|sector_breakdown|global_markets|major_indexes", "top_movers").option("--period <p>", "1d|1w|1m|3m|6m|ytd|1y|5y", "1d").option("--limit <n>", "Max stocks for top_movers", "24").option("--universe <u>", "all|sp500|international|crypto|community", "all")
515
539
  ).action(async (opts) => {
516
540
  const data = await callTool("get_market_map", {
517
541
  map_type: opts.type,
518
542
  period: opts.period,
519
- limit: parseIntSafe(opts.limit, 24)
543
+ limit: parseIntSafe(opts.limit, 24),
544
+ universe: opts.universe
520
545
  });
521
546
  outputResult(data, opts);
522
547
  });
@@ -601,6 +626,40 @@ function registerEarningsCommand(program2) {
601
626
  });
602
627
  }
603
628
 
629
+ // src/commands/earnings-calendar.ts
630
+ function registerEarningsCalendarCommand(program2) {
631
+ addGlobalOptions(
632
+ program2.command("earnings-calendar").description(
633
+ "Upcoming earnings dates for symbols (default 28 days)"
634
+ ).argument("<symbols...>", "Ticker symbols").option("--days <n>", "Look-ahead window in days (1-90)", "28")
635
+ ).action(
636
+ async (symbols, opts) => {
637
+ const days = parseIntSafe(opts.days, 28);
638
+ const syms = symbols.map((s) => s.toUpperCase()).join(",");
639
+ const data = await callRest("/markets/earnings-calendar/", {
640
+ symbols: syms,
641
+ days: String(days)
642
+ });
643
+ const items = data.results ?? [];
644
+ outputResult(items, opts, (d, o) => {
645
+ const rows = d;
646
+ if (rows.length === 0) return "(no upcoming earnings)";
647
+ return makeTable(
648
+ ["Date", "Symbol", "Name", "Est. EPS", "Actual EPS"],
649
+ rows.map((r) => [
650
+ r.earnings_date ?? "\u2014",
651
+ r.symbol,
652
+ r.name,
653
+ r.eps_estimate != null ? `$${r.eps_estimate}` : "\u2014",
654
+ r.eps_actual != null ? `$${r.eps_actual}` : "\u2014"
655
+ ]),
656
+ o
657
+ );
658
+ });
659
+ }
660
+ );
661
+ }
662
+
604
663
  // src/commands/technicals.ts
605
664
  var SECTIONS2 = ["technical_indicators", "options_analysis", "insider_activity"];
606
665
  function registerTechnicalsCommand(program2) {
@@ -895,11 +954,682 @@ function formatPortfolios(data, opts) {
895
954
  return lines.join("\n");
896
955
  }
897
956
 
957
+ // src/commands/ma.ts
958
+ function formatTable(data, limit) {
959
+ const { symbol, current_price, indicators } = data;
960
+ const labels = Object.keys(indicators);
961
+ if (labels.length === 0) {
962
+ console.log(`No indicator data returned for ${symbol}`);
963
+ return;
964
+ }
965
+ const allDates = /* @__PURE__ */ new Set();
966
+ for (const label of labels) {
967
+ const ind = indicators[label];
968
+ if ("error" in ind) continue;
969
+ for (const date of Object.keys(ind)) {
970
+ allDates.add(date);
971
+ }
972
+ }
973
+ const sortedDates = Array.from(allDates).sort((a, b) => b.localeCompare(a)).slice(0, limit).reverse();
974
+ if (sortedDates.length === 0) {
975
+ console.log(`No data points available for ${symbol}`);
976
+ return;
977
+ }
978
+ const dateWidth = 12;
979
+ const colWidth = 12;
980
+ const header = "Date".padEnd(dateWidth) + labels.map((l) => l.toUpperCase().padStart(colWidth)).join("");
981
+ const divider = "-".repeat(dateWidth + colWidth * labels.length);
982
+ console.log(`
983
+ ${symbol}${current_price != null ? ` (current: $${current_price.toFixed(2)})` : ""}`);
984
+ console.log(divider);
985
+ console.log(header);
986
+ console.log(divider);
987
+ for (const date of sortedDates) {
988
+ let row = date.padEnd(dateWidth);
989
+ for (const label of labels) {
990
+ const ind = indicators[label];
991
+ if ("error" in ind) {
992
+ row += "N/A".padStart(colWidth);
993
+ } else {
994
+ const val = ind[date];
995
+ row += (val != null ? val.toFixed(2) : "\u2014").padStart(colWidth);
996
+ }
997
+ }
998
+ console.log(row);
999
+ }
1000
+ console.log(divider);
1001
+ console.log(`Showing ${sortedDates.length} data point(s)
1002
+ `);
1003
+ }
1004
+ function registerMaCommand(program2) {
1005
+ addGlobalOptions(
1006
+ program2.command("ma").description("Moving averages (SMA/EMA) for a symbol").argument("<symbol>", "Ticker symbol (e.g., AAPL)").option("--sma <periods>", "Comma-separated SMA periods (e.g., 50,100,200)").option("--ema <periods>", "Comma-separated EMA periods (e.g., 20,50)").option("--limit <n>", "Number of data points to display (default: 20)", "20")
1007
+ ).action(
1008
+ async (symbol, opts) => {
1009
+ const indicators = [];
1010
+ if (opts.sma) {
1011
+ for (const p of opts.sma.split(",")) {
1012
+ const period = p.trim();
1013
+ if (period) indicators.push(`sma_${period}`);
1014
+ }
1015
+ }
1016
+ if (opts.ema) {
1017
+ for (const p of opts.ema.split(",")) {
1018
+ const period = p.trim();
1019
+ if (period) indicators.push(`ema_${period}`);
1020
+ }
1021
+ }
1022
+ if (indicators.length === 0) {
1023
+ indicators.push("sma_100", "ema_100");
1024
+ }
1025
+ const args = {
1026
+ symbol: symbol.toUpperCase(),
1027
+ indicators
1028
+ };
1029
+ const data = await callTool("get_moving_averages", args);
1030
+ const limit = parseInt(opts.limit, 10) || 20;
1031
+ let parsed = null;
1032
+ try {
1033
+ parsed = typeof data === "string" ? JSON.parse(data) : data;
1034
+ } catch {
1035
+ }
1036
+ if (parsed?.indicators && typeof parsed.indicators === "object") {
1037
+ const allDates = /* @__PURE__ */ new Set();
1038
+ for (const ind of Object.values(parsed.indicators)) {
1039
+ if ("error" in ind) continue;
1040
+ for (const date of Object.keys(ind)) {
1041
+ allDates.add(date);
1042
+ }
1043
+ }
1044
+ const keepDates = new Set(
1045
+ Array.from(allDates).sort((a, b) => b.localeCompare(a)).slice(0, limit)
1046
+ );
1047
+ for (const [label, ind] of Object.entries(parsed.indicators)) {
1048
+ if ("error" in ind) continue;
1049
+ const filtered = {};
1050
+ for (const [date, val] of Object.entries(ind)) {
1051
+ if (keepDates.has(date)) filtered[date] = val;
1052
+ }
1053
+ parsed.indicators[label] = filtered;
1054
+ }
1055
+ }
1056
+ if (opts.output || opts.format || opts.raw || !process.stdout.isTTY) {
1057
+ outputResult(parsed ?? data, opts);
1058
+ return;
1059
+ }
1060
+ if (parsed?.indicators && typeof parsed.indicators === "object") {
1061
+ formatTable(parsed, limit);
1062
+ } else {
1063
+ outputResult(data, opts);
1064
+ }
1065
+ }
1066
+ );
1067
+ }
1068
+
1069
+ // src/commands/backtest.ts
1070
+ function registerBacktestCommand(program2) {
1071
+ addGlobalOptions(
1072
+ program2.command("backtest").description("Backtest a portfolio against a benchmark").requiredOption("--symbols <s>", "Comma-separated symbols (e.g., AAPL,MSFT)").requiredOption("--allocations <a>", "Comma-separated weights (e.g., 0.5,0.5)").option("--benchmark <b>", "Benchmark symbol (default: SPY)", "SPY").option("--strategy <s>", "Strategy: buy_and_hold", "buy_and_hold")
1073
+ ).action(async (opts) => {
1074
+ const data = await callRest("backtest/", {
1075
+ symbols: opts.symbols,
1076
+ allocations: opts.allocations,
1077
+ benchmark: opts.benchmark,
1078
+ strategy: opts.strategy
1079
+ });
1080
+ outputResult(data, opts, formatBacktest);
1081
+ });
1082
+ }
1083
+ function formatBacktest(data) {
1084
+ const obj = data;
1085
+ if (!obj || typeof obj !== "object") return JSON.stringify(data, null, 2);
1086
+ const intervals = obj.interval_results ?? obj;
1087
+ const rows = [];
1088
+ for (const [interval, stats] of Object.entries(intervals)) {
1089
+ if (typeof stats !== "object" || !stats) continue;
1090
+ const s = stats;
1091
+ rows.push([
1092
+ interval,
1093
+ fmt(s.total_return),
1094
+ fmt(s.benchmark_return),
1095
+ fmt(s.alpha ?? s.excess_return),
1096
+ fmtNum(s.sharpe),
1097
+ fmt(s.max_drawdown)
1098
+ ]);
1099
+ }
1100
+ if (rows.length === 0) return JSON.stringify(data, null, 2);
1101
+ return makeTable(["Interval", "Return", "Benchmark", "Alpha", "Sharpe", "Max DD"], rows);
1102
+ }
1103
+ function fmt(v) {
1104
+ if (v == null || v === "") return "-";
1105
+ const n = Number(v);
1106
+ if (isNaN(n)) return String(v);
1107
+ return `${(n * 100).toFixed(2)}%`;
1108
+ }
1109
+ function fmtNum(v) {
1110
+ if (v == null || v === "") return "-";
1111
+ const n = Number(v);
1112
+ if (isNaN(n)) return String(v);
1113
+ return n.toFixed(3);
1114
+ }
1115
+
1116
+ // src/commands/correlation.ts
1117
+ function registerCorrelationCommand(program2) {
1118
+ addGlobalOptions(
1119
+ program2.command("correlation").description("Correlation matrix for a set of symbols").argument("<symbols...>", "Ticker symbols (2+)").option("--start <date>", "Start date (YYYY-MM-DD)").option("--end <date>", "End date (YYYY-MM-DD)")
1120
+ ).action(async (symbols, opts) => {
1121
+ const params = {
1122
+ symbols: symbols.map((s) => s.toUpperCase()).join(",")
1123
+ };
1124
+ if (opts.start) params.start_date = opts.start;
1125
+ if (opts.end) params.end_date = opts.end;
1126
+ const data = await callRest("correlation/", params);
1127
+ outputResult(data, opts, formatCorrelation);
1128
+ });
1129
+ }
1130
+ function formatCorrelation(data) {
1131
+ const obj = data;
1132
+ const matrix = obj?.correlation;
1133
+ if (!matrix) return JSON.stringify(data, null, 2);
1134
+ const symbols = Object.keys(matrix);
1135
+ const rows = symbols.map((s) => [s, ...symbols.map((s2) => {
1136
+ const v = matrix[s]?.[s2];
1137
+ return v != null ? v.toFixed(3) : "-";
1138
+ })]);
1139
+ return makeTable(["", ...symbols], rows);
1140
+ }
1141
+
1142
+ // src/commands/risk.ts
1143
+ function registerRiskCommand(program2) {
1144
+ addGlobalOptions(
1145
+ program2.command("risk").description("Risk factors for a stock").argument("<symbol>", "Ticker symbol")
1146
+ ).action(async (symbol, opts) => {
1147
+ const data = await callRest(`investments/${symbol.toUpperCase()}/risk_factors/`);
1148
+ outputResult(data, opts, formatRisk);
1149
+ });
1150
+ }
1151
+ function formatRisk(data) {
1152
+ if (!Array.isArray(data)) return JSON.stringify(data, null, 2);
1153
+ if (data.length === 0) return "(no risk factors found)";
1154
+ const rows = data.map((r) => [
1155
+ String(r.category ?? r.risk_type ?? "-"),
1156
+ truncate3(String(r.description ?? r.text ?? "-"), 80)
1157
+ ]);
1158
+ return makeTable(["Category", "Description"], rows);
1159
+ }
1160
+ function truncate3(s, max) {
1161
+ return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
1162
+ }
1163
+
1164
+ // src/commands/drawdown.ts
1165
+ function registerDrawdownCommand(program2) {
1166
+ addGlobalOptions(
1167
+ program2.command("drawdown").description("Portfolio drawdown analysis").requiredOption("--symbols <s>", "Comma-separated symbols (e.g., AAPL,MSFT)").requiredOption("--allocations <a>", "Comma-separated weights (e.g., 0.5,0.5)")
1168
+ ).action(async (opts) => {
1169
+ const data = await callRest("portfolios/drawdown/", {
1170
+ symbols: opts.symbols,
1171
+ allocations: opts.allocations
1172
+ });
1173
+ outputResult(data, opts, formatDrawdown);
1174
+ });
1175
+ }
1176
+ function formatDrawdown(data) {
1177
+ const obj = data;
1178
+ if (!obj || typeof obj !== "object") return JSON.stringify(data, null, 2);
1179
+ const intervals = obj.interval_results ?? obj;
1180
+ const rows = [];
1181
+ for (const [interval, dd] of Object.entries(intervals)) {
1182
+ if (typeof dd !== "object" || !dd) continue;
1183
+ const d = dd;
1184
+ let troughDate = "-";
1185
+ let recoveryDate = "not recovered";
1186
+ const plotData = d.plot_data;
1187
+ if (plotData && plotData.length > 0) {
1188
+ let minDD = 0;
1189
+ let minIdx = -1;
1190
+ for (let i = 0; i < plotData.length; i++) {
1191
+ if (plotData[i].drawdown < minDD) {
1192
+ minDD = plotData[i].drawdown;
1193
+ minIdx = i;
1194
+ }
1195
+ }
1196
+ if (minIdx >= 0) {
1197
+ troughDate = plotData[minIdx].date;
1198
+ for (let i = minIdx + 1; i < plotData.length; i++) {
1199
+ if (plotData[i].drawdown >= 0) {
1200
+ recoveryDate = plotData[i].date;
1201
+ break;
1202
+ }
1203
+ }
1204
+ }
1205
+ }
1206
+ rows.push([
1207
+ interval,
1208
+ d.max_drawdown != null ? `${(Number(d.max_drawdown) * 100).toFixed(2)}%` : "-",
1209
+ troughDate,
1210
+ recoveryDate
1211
+ ]);
1212
+ }
1213
+ if (rows.length === 0) return JSON.stringify(data, null, 2);
1214
+ return makeTable(["Interval", "Max Drawdown", "Trough Date", "Recovery"], rows);
1215
+ }
1216
+
1217
+ // src/commands/macro.ts
1218
+ function registerMacroCommand(program2) {
1219
+ addGlobalOptions(
1220
+ program2.command("macro").description("Macroeconomic indicators (GDP, CPI, unemployment, fed funds, treasury, inflation)").option("--indicators <list>", "Comma-separated: GDP,CPI,UNEMPLOYMENT,FED_FUNDS,TREASURY_10Y,INFLATION")
1221
+ ).action(async (opts) => {
1222
+ const args = {};
1223
+ if (opts.indicators) {
1224
+ args.indicators = opts.indicators;
1225
+ }
1226
+ const data = await callTool("get_macro_indicators", args);
1227
+ outputResult(data, opts, formatMacro);
1228
+ });
1229
+ }
1230
+ function formatMacro(data) {
1231
+ const obj = data;
1232
+ const rows = [];
1233
+ for (const [name, raw] of Object.entries(obj)) {
1234
+ const d = raw;
1235
+ if (d.error) {
1236
+ rows.push([name, "-", "-", "-", "-"]);
1237
+ continue;
1238
+ }
1239
+ const points = d.data;
1240
+ if (!points || points.length === 0) {
1241
+ rows.push([name, "-", "-", "-", "-"]);
1242
+ continue;
1243
+ }
1244
+ const latest = points[0];
1245
+ const prev = points.length > 1 ? points[1] : null;
1246
+ const latestVal = latest.value;
1247
+ const prevVal = prev?.value ?? "-";
1248
+ const change = latestVal !== "." && prevVal !== "-" && prevVal !== "." ? (Number(latestVal) - Number(prevVal)).toFixed(2) : "-";
1249
+ rows.push([name, String(d.unit ?? ""), latestVal, latest.date, change]);
1250
+ }
1251
+ return makeTable(["Indicator", "Unit", "Latest", "Date", "Change"], rows);
1252
+ }
1253
+
1254
+ // src/commands/sectors.ts
1255
+ function registerSectorsCommand(program2) {
1256
+ addGlobalOptions(
1257
+ program2.command("sectors").description("Sector performance across time periods")
1258
+ ).action(async (opts) => {
1259
+ const data = await callTool("get_sector_performance", {});
1260
+ outputResult(data, opts, formatSectors);
1261
+ });
1262
+ }
1263
+ var PERIOD_KEYS = [
1264
+ "Rank A: Real-Time Performance",
1265
+ "Rank B: 1 Day Performance",
1266
+ "Rank C: 5 Day Performance",
1267
+ "Rank D: 1 Month Performance",
1268
+ "Rank E: 3 Month Performance",
1269
+ "Rank F: Year-to-Date (YTD) Performance",
1270
+ "Rank G: 1 Year Performance",
1271
+ "Rank H: 3 Year Performance",
1272
+ "Rank I: 5 Year Performance",
1273
+ "Rank J: 10 Year Performance"
1274
+ ];
1275
+ var PERIOD_LABELS = [
1276
+ "Real-Time",
1277
+ "1 Day",
1278
+ "5 Day",
1279
+ "1 Month",
1280
+ "3 Month",
1281
+ "YTD",
1282
+ "1 Year",
1283
+ "3 Year",
1284
+ "5 Year",
1285
+ "10 Year"
1286
+ ];
1287
+ function formatSectors(data) {
1288
+ const obj = data;
1289
+ const sectors = /* @__PURE__ */ new Set();
1290
+ for (const key of PERIOD_KEYS) {
1291
+ const period = obj[key];
1292
+ if (period) {
1293
+ for (const sector of Object.keys(period)) sectors.add(sector);
1294
+ }
1295
+ }
1296
+ if (sectors.size === 0) return JSON.stringify(data, null, 2);
1297
+ const sectorList = Array.from(sectors).sort();
1298
+ const rows = sectorList.map((sector) => {
1299
+ const vals = PERIOD_KEYS.map((key) => {
1300
+ const v = obj[key]?.[sector];
1301
+ return v ?? "-";
1302
+ });
1303
+ return [sector, ...vals];
1304
+ });
1305
+ return makeTable(["Sector", ...PERIOD_LABELS], rows);
1306
+ }
1307
+
1308
+ // src/commands/dcf.ts
1309
+ function registerDcfCommand(program2) {
1310
+ addGlobalOptions(
1311
+ program2.command("dcf").description("Discounted cash flow valuation").argument("<symbol>", "Ticker symbol")
1312
+ ).action(async (symbol, opts) => {
1313
+ const sym = symbol.toUpperCase();
1314
+ const result = await callTool("get_dcf_valuation", { symbol: sym });
1315
+ outputResult(result, opts, () => formatDcf(result, sym));
1316
+ });
1317
+ }
1318
+ function formatDcf(data, symbol) {
1319
+ const rows = [];
1320
+ const obj = data;
1321
+ const dcf = obj?.dcf;
1322
+ const d = Array.isArray(dcf) ? dcf[0] : dcf;
1323
+ if (d && typeof d === "object") {
1324
+ const price = Number(d.Stock_Price ?? d.stockPrice ?? 0);
1325
+ const dcfVal = Number(d.DCF ?? d.dcf ?? 0);
1326
+ const upside = price > 0 ? ((dcfVal - price) / price * 100).toFixed(1) : "-";
1327
+ rows.push(["Current Price", `$${price.toFixed(2)}`]);
1328
+ rows.push(["DCF Value", `$${dcfVal.toFixed(2)}`]);
1329
+ rows.push(["Upside/Downside", `${upside}%`]);
1330
+ }
1331
+ if (rows.length === 0) return `No DCF data available for ${symbol}`;
1332
+ return makeTable(["Metric", "Value"], rows);
1333
+ }
1334
+
1335
+ // src/commands/holders.ts
1336
+ function registerHoldersCommand(program2) {
1337
+ addGlobalOptions(
1338
+ program2.command("holders").description("Institutional and mutual fund holders").argument("<symbol>", "Ticker symbol").option("--type <t>", "institutional or mutual-fund (default: both)").option("--limit <n>", "Max holders to show", "15")
1339
+ ).action(async (symbol, opts) => {
1340
+ const sym = symbol.toUpperCase();
1341
+ const limit = parseIntSafe(opts.limit, 15);
1342
+ const args = { symbol: sym };
1343
+ if (opts.type) args.holder_type = opts.type;
1344
+ const data = await callTool("get_holders", args);
1345
+ outputResult(data, opts, () => formatHolders(data, limit));
1346
+ });
1347
+ }
1348
+ function formatHolders(data, limit) {
1349
+ const parts = [];
1350
+ const addSection = (title, list) => {
1351
+ const items = list;
1352
+ if (items && items.length > 0) {
1353
+ const rows = items.slice(0, limit).map((h) => [
1354
+ String(h.holder ?? "-"),
1355
+ fmtNum2(h.shares),
1356
+ h.dateReported ? String(h.dateReported).slice(0, 10) : "-",
1357
+ fmtNum2(h.change)
1358
+ ]);
1359
+ parts.push(`${title}
1360
+ ${makeTable(["Holder", "Shares", "Date", "Change"], rows)}`);
1361
+ }
1362
+ };
1363
+ addSection("INSTITUTIONAL HOLDERS", data.institutional);
1364
+ addSection("MUTUAL FUND HOLDERS", data.mutual_fund);
1365
+ return parts.length > 0 ? parts.join("\n\n") : "(no holder data found)";
1366
+ }
1367
+ function fmtNum2(v) {
1368
+ if (v == null) return "-";
1369
+ const n = Number(v);
1370
+ if (isNaN(n)) return String(v);
1371
+ if (Math.abs(n) >= 1e9) return `${(n / 1e9).toFixed(2)}B`;
1372
+ if (Math.abs(n) >= 1e6) return `${(n / 1e6).toFixed(2)}M`;
1373
+ if (Math.abs(n) >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
1374
+ return n.toLocaleString();
1375
+ }
1376
+
1377
+ // src/commands/short-interest.ts
1378
+ function registerShortInterestCommand(program2) {
1379
+ addGlobalOptions(
1380
+ program2.command("short-interest").description("Short interest history").argument("<symbol>", "Ticker symbol").option("--limit <n>", "Number of records", "10")
1381
+ ).action(async (symbol, opts) => {
1382
+ const sym = symbol.toUpperCase();
1383
+ const limit = parseIntSafe(opts.limit, 10);
1384
+ const data = await callTool("get_short_interest", { symbol: sym, limit });
1385
+ outputResult(data, opts, formatShort);
1386
+ });
1387
+ }
1388
+ function formatShort(data) {
1389
+ if (!Array.isArray(data) || data.length === 0) return "(no short interest data)";
1390
+ const rows = data.map((r) => [
1391
+ String(r.date ?? "-"),
1392
+ fmtNum3(r.shortInterest),
1393
+ String(r.daysToCover ?? r.daysTocover ?? "-"),
1394
+ String(r.shortInterestRatio ?? "-"),
1395
+ fmtNum3(r.shortPriorMonthInterest ?? r.shortPriorMonth),
1396
+ r.changePercent != null ? `${Number(r.changePercent).toFixed(2)}%` : "-"
1397
+ ]);
1398
+ return makeTable(["Date", "Short Interest", "Days to Cover", "Short Ratio", "Prior Month", "Change %"], rows);
1399
+ }
1400
+ function fmtNum3(v) {
1401
+ if (v == null) return "-";
1402
+ const n = Number(v);
1403
+ if (isNaN(n)) return String(v);
1404
+ if (Math.abs(n) >= 1e9) return `${(n / 1e9).toFixed(2)}B`;
1405
+ if (Math.abs(n) >= 1e6) return `${(n / 1e6).toFixed(2)}M`;
1406
+ if (Math.abs(n) >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
1407
+ return n.toLocaleString();
1408
+ }
1409
+
1410
+ // src/commands/insider.ts
1411
+ function registerInsiderCommand(program2) {
1412
+ addGlobalOptions(
1413
+ program2.command("insider").description("Insider trading activity (SEC Form 4)").argument("<symbol>", "Ticker symbol").option("--limit <n>", "Max transactions to show", "20")
1414
+ ).action(async (symbol, opts) => {
1415
+ const sym = symbol.toUpperCase();
1416
+ const limit = parseIntSafe(opts.limit, 20);
1417
+ const data = await callTool("get_insider_trading", { symbol: sym, limit });
1418
+ outputResult(data, opts, formatInsider);
1419
+ });
1420
+ }
1421
+ function formatInsider(data) {
1422
+ if (!Array.isArray(data) || data.length === 0) return "(no insider trading data)";
1423
+ const rows = data.map((t) => {
1424
+ const val = t.securitiesTransacted && t.price ? `$${(Number(t.securitiesTransacted) * Number(t.price)).toLocaleString()}` : "-";
1425
+ return [
1426
+ String(t.filingDate ?? t.transactionDate ?? "-").slice(0, 10),
1427
+ String(t.reportingName ?? "-"),
1428
+ String(t.typeOfOwner ?? "-"),
1429
+ String(t.transactionType ?? t.acquistionOrDisposition ?? "-"),
1430
+ fmtNum4(t.securitiesTransacted),
1431
+ t.price != null ? `$${Number(t.price).toFixed(2)}` : "-",
1432
+ val
1433
+ ];
1434
+ });
1435
+ return makeTable(["Date", "Name", "Title", "Type", "Shares", "Price", "Value"], rows);
1436
+ }
1437
+ function fmtNum4(v) {
1438
+ if (v == null) return "-";
1439
+ const n = Number(v);
1440
+ if (isNaN(n)) return String(v);
1441
+ return n.toLocaleString();
1442
+ }
1443
+
1444
+ // src/commands/dividends.ts
1445
+ function registerDividendsCommand(program2) {
1446
+ addGlobalOptions(
1447
+ program2.command("dividends").description("Dividend history for a stock").argument("<symbol>", "Ticker symbol").option("--limit <n>", "Number of records", "20").option("--from <date>", "Start date (YYYY-MM-DD)")
1448
+ ).action(async (symbol, opts) => {
1449
+ const sym = symbol.toUpperCase();
1450
+ const limit = parseIntSafe(opts.limit, 20);
1451
+ const args = { symbol: sym, limit };
1452
+ if (opts.from) args.from_date = opts.from;
1453
+ const data = await callTool("get_dividends", args);
1454
+ outputResult(data, opts, formatDividends);
1455
+ });
1456
+ }
1457
+ function formatDividends(data) {
1458
+ if (!Array.isArray(data) || data.length === 0) return "(no dividend data)";
1459
+ const rows = data.map((d) => [
1460
+ String(d.date ?? "-"),
1461
+ d.value != null ? `$${Number(d.value).toFixed(4)}` : "-",
1462
+ String(d.declarationDate ?? "-"),
1463
+ String(d.recordDate ?? "-"),
1464
+ String(d.paymentDate ?? "-"),
1465
+ String(d.period ?? "-")
1466
+ ]);
1467
+ return makeTable(["Ex-Date", "Amount", "Declaration", "Record", "Payment", "Period"], rows);
1468
+ }
1469
+
1470
+ // src/commands/splits.ts
1471
+ function registerSplitsCommand(program2) {
1472
+ addGlobalOptions(
1473
+ program2.command("splits").description("Stock split history").argument("<symbol>", "Ticker symbol").option("--from <date>", "Start date (YYYY-MM-DD)")
1474
+ ).action(async (symbol, opts) => {
1475
+ const sym = symbol.toUpperCase();
1476
+ const args = { symbol: sym };
1477
+ if (opts.from) args.from_date = opts.from;
1478
+ const data = await callTool("get_splits", args);
1479
+ outputResult(data, opts, formatSplits);
1480
+ });
1481
+ }
1482
+ function formatSplits(data) {
1483
+ if (!Array.isArray(data) || data.length === 0) return "(no stock splits found)";
1484
+ const rows = data.map((s) => [
1485
+ String(s.date ?? "-"),
1486
+ String(s.split ?? "-")
1487
+ ]);
1488
+ return makeTable(["Date", "Split Ratio"], rows);
1489
+ }
1490
+
1491
+ // src/commands/ipo.ts
1492
+ function registerIpoCommand(program2) {
1493
+ addGlobalOptions(
1494
+ program2.command("ipo").description("Upcoming and recent IPOs").option("--from <date>", "Start date (YYYY-MM-DD)").option("--to <date>", "End date (YYYY-MM-DD)")
1495
+ ).action(async (opts) => {
1496
+ const args = {};
1497
+ if (opts.from) args.from_date = opts.from;
1498
+ if (opts.to) args.to_date = opts.to;
1499
+ const data = await callTool("get_ipo_calendar", args);
1500
+ outputResult(data, opts, formatIpos);
1501
+ });
1502
+ }
1503
+ function formatIpos(data) {
1504
+ const ipos = Array.isArray(data) ? data : data?.ipos;
1505
+ if (!Array.isArray(ipos) || ipos.length === 0) return "(no IPO data found)";
1506
+ const rows = ipos.map((ipo) => [
1507
+ String(ipo.date ?? ipo.start_date ?? "-"),
1508
+ String(ipo.name ?? ipo.company ?? "-"),
1509
+ String(ipo.code ?? ipo.ticker ?? ipo.symbol ?? "-"),
1510
+ String(ipo.exchange ?? "-"),
1511
+ ipo.price_from && ipo.price_to ? `$${ipo.price_from}-$${ipo.price_to}` : ipo.price ? `$${ipo.price}` : "-",
1512
+ ipo.shares ? fmtNum5(ipo.shares) : "-"
1513
+ ]);
1514
+ return makeTable(["Date", "Company", "Symbol", "Exchange", "Price Range", "Shares"], rows);
1515
+ }
1516
+ function fmtNum5(v) {
1517
+ if (v == null) return "-";
1518
+ const n = Number(v);
1519
+ if (isNaN(n)) return String(v);
1520
+ if (Math.abs(n) >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
1521
+ return n.toLocaleString();
1522
+ }
1523
+
1524
+ // src/commands/compare.ts
1525
+ function registerCompareCommand(program2) {
1526
+ addGlobalOptions(
1527
+ program2.command("compare").description("Side-by-side comparison of stocks").argument("<symbols...>", "Ticker symbols (2-10)")
1528
+ ).action(async (symbols, opts) => {
1529
+ const syms = symbols.map((s) => s.toUpperCase()).slice(0, 10);
1530
+ const data = await callTool("get_symbols_metadata", { symbols: syms });
1531
+ outputResult(data, opts, (d) => formatComparison(d, syms));
1532
+ });
1533
+ }
1534
+ function formatComparison(data, symbols) {
1535
+ const obj = data;
1536
+ const list = obj?.symbols ?? (Array.isArray(data) ? data : null);
1537
+ if (!Array.isArray(list) || list.length === 0) return JSON.stringify(data, null, 2);
1538
+ const metrics = [
1539
+ ["Price", "latest_price", "$"],
1540
+ ["Market Cap", "market_cap", "cap"],
1541
+ ["P/E", "pe_ratio", ""],
1542
+ ["EPS", "eps", "$"],
1543
+ ["Dividend Yield", "dividend_yield", "%"],
1544
+ ["52W High", "week_52_high", "$"],
1545
+ ["52W Low", "week_52_low", "$"],
1546
+ ["Beta", "beta", ""],
1547
+ ["Sector", "sector", ""]
1548
+ ];
1549
+ const bySymbol = {};
1550
+ for (const item of list) {
1551
+ const i = item;
1552
+ const meta = i.basic_metadata ?? i;
1553
+ const sym = String(meta.symbol ?? i.symbol ?? "");
1554
+ bySymbol[sym] = meta;
1555
+ }
1556
+ const headers = ["Metric", ...symbols];
1557
+ const rows = metrics.map(([label, key, fmt2]) => {
1558
+ const vals = symbols.map((s) => {
1559
+ const meta = bySymbol[s];
1560
+ if (!meta) return "-";
1561
+ const v = meta[key];
1562
+ if (v == null) return "-";
1563
+ if (fmt2 === "$") return `$${Number(v).toFixed(2)}`;
1564
+ if (fmt2 === "%") return `${(Number(v) * 100).toFixed(2)}%`;
1565
+ if (fmt2 === "cap") return fmtCap(v);
1566
+ return String(v);
1567
+ });
1568
+ return [label, ...vals];
1569
+ });
1570
+ return makeTable(headers, rows);
1571
+ }
1572
+ function fmtCap(v) {
1573
+ const n = Number(v);
1574
+ if (isNaN(n)) return String(v);
1575
+ if (n >= 1e12) return `$${(n / 1e12).toFixed(2)}T`;
1576
+ if (n >= 1e9) return `$${(n / 1e9).toFixed(2)}B`;
1577
+ if (n >= 1e6) return `$${(n / 1e6).toFixed(0)}M`;
1578
+ return `$${n.toLocaleString()}`;
1579
+ }
1580
+
1581
+ // src/commands/ratings.ts
1582
+ function registerRatingsCommand(program2) {
1583
+ addGlobalOptions(
1584
+ program2.command("ratings").description("Analyst ratings, grades, and price targets").argument("<symbol>", "Ticker symbol").option("--limit <n>", "Max records to show", "20")
1585
+ ).action(async (symbol, opts) => {
1586
+ const sym = symbol.toUpperCase();
1587
+ const limit = parseIntSafe(opts.limit, 20);
1588
+ const result = await callTool("get_analyst_ratings", { symbol: sym, limit });
1589
+ outputResult(result, opts, () => {
1590
+ const obj = result;
1591
+ return formatRatings(obj.grades, obj.estimates);
1592
+ });
1593
+ });
1594
+ }
1595
+ function formatRatings(grades, estimates) {
1596
+ const parts = [];
1597
+ if (Array.isArray(grades) && grades.length > 0) {
1598
+ const rows = grades.map((g) => [
1599
+ String(g.date ?? "-").slice(0, 10),
1600
+ String(g.gradingCompany ?? "-"),
1601
+ String(g.previousGrade ?? "-"),
1602
+ String(g.newGrade ?? "-"),
1603
+ String(g.action ?? "-")
1604
+ ]);
1605
+ parts.push("ANALYST GRADES\n" + makeTable(["Date", "Firm", "Previous", "New", "Action"], rows));
1606
+ }
1607
+ if (Array.isArray(estimates) && estimates.length > 0) {
1608
+ const rows = estimates.map((e) => [
1609
+ String(e.date ?? "-").slice(0, 10),
1610
+ e.estimatedRevenueAvg != null ? fmtNum6(e.estimatedRevenueAvg) : "-",
1611
+ e.estimatedEpsAvg != null ? `$${Number(e.estimatedEpsAvg).toFixed(2)}` : "-",
1612
+ String(e.numberAnalystEstimatedRevenue ?? e.numberAnalystsEstimatedRevenue ?? "-")
1613
+ ]);
1614
+ parts.push("ANALYST ESTIMATES\n" + makeTable(["Period", "Est. Revenue", "Est. EPS", "# Analysts"], rows));
1615
+ }
1616
+ return parts.length > 0 ? parts.join("\n\n") : "(no ratings data found)";
1617
+ }
1618
+ function fmtNum6(v) {
1619
+ if (v == null) return "-";
1620
+ const n = Number(v);
1621
+ if (isNaN(n)) return String(v);
1622
+ if (Math.abs(n) >= 1e12) return `$${(n / 1e12).toFixed(2)}T`;
1623
+ if (Math.abs(n) >= 1e9) return `$${(n / 1e9).toFixed(2)}B`;
1624
+ if (Math.abs(n) >= 1e6) return `$${(n / 1e6).toFixed(0)}M`;
1625
+ return `$${n.toLocaleString()}`;
1626
+ }
1627
+
898
1628
  // src/index.ts
899
1629
  var program = new Command();
900
1630
  var __dirname = path.dirname(fileURLToPath(import.meta.url));
901
1631
  var pkgPath = path.join(__dirname, "..", "package.json");
902
- var compiledVersion = "0.1.3".length > 0 ? "0.1.3" : void 0;
1632
+ var compiledVersion = "0.1.5".length > 0 ? "0.1.5" : void 0;
903
1633
  var envVersion = process.env.BLOOM_CLI_VERSION ?? process.env.npm_package_version;
904
1634
  var fallbackVersion = compiledVersion ?? "unknown";
905
1635
  var cliVersion = envVersion ?? fallbackVersion;
@@ -924,6 +1654,7 @@ registerMarketCommand(program);
924
1654
  registerCollectionsCommand(program);
925
1655
  registerScreenCommand(program);
926
1656
  registerEarningsCommand(program);
1657
+ registerEarningsCalendarCommand(program);
927
1658
  registerTechnicalsCommand(program);
928
1659
  registerOptionsCommand(program);
929
1660
  registerPortfolioCommand(program);
@@ -933,6 +1664,22 @@ registerPositionCommand(program);
933
1664
  registerTranscriptCommand(program);
934
1665
  registerAiTradesCommand(program);
935
1666
  registerAiPortfolioCommand(program);
1667
+ registerMaCommand(program);
1668
+ registerBacktestCommand(program);
1669
+ registerCorrelationCommand(program);
1670
+ registerRiskCommand(program);
1671
+ registerDrawdownCommand(program);
1672
+ registerMacroCommand(program);
1673
+ registerSectorsCommand(program);
1674
+ registerDcfCommand(program);
1675
+ registerHoldersCommand(program);
1676
+ registerShortInterestCommand(program);
1677
+ registerInsiderCommand(program);
1678
+ registerDividendsCommand(program);
1679
+ registerSplitsCommand(program);
1680
+ registerIpoCommand(program);
1681
+ registerCompareCommand(program);
1682
+ registerRatingsCommand(program);
936
1683
  program.parseAsync().catch((err) => {
937
1684
  console.error("Error:", err.message || err);
938
1685
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bloomai/cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "CLI tool for Bloom financial data - download market data to files for analysis",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,7 +13,8 @@
13
13
  ],
14
14
  "scripts": {
15
15
  "build": "tsup",
16
- "dev": "tsup --watch"
16
+ "dev": "tsup --watch",
17
+ "test": "vitest run"
17
18
  },
18
19
  "keywords": [
19
20
  "finance",
@@ -30,6 +31,7 @@
30
31
  "devDependencies": {
31
32
  "@types/node": "^22.13.0",
32
33
  "tsup": "^8.4.0",
33
- "typescript": "^5.7.0"
34
+ "typescript": "^5.7.0",
35
+ "vitest": "^4.1.5"
34
36
  }
35
37
  }