@bloomai/cli 0.1.2 → 0.1.3
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 +23 -0
- package/SKILL.md +23 -0
- package/dist/index.js +130 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -52,6 +52,8 @@ jq '.data[] | select(.revenue_growth > 0.1)' /tmp/bloom/aapl-revenue.json
|
|
|
52
52
|
| `catalysts` | Forward-looking value drivers | `bloom catalysts AAPL MSFT` |
|
|
53
53
|
| `position-size` | Kelly criterion sizing | `bloom position-size --bull 0.6 --bear -0.15 --conviction 8 --value 100000` |
|
|
54
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` |
|
|
56
|
+
| `ai-portfolio` | AI model portfolio positions & performance | `bloom ai-portfolio --model openai` |
|
|
55
57
|
|
|
56
58
|
## Global Flags
|
|
57
59
|
|
|
@@ -115,6 +117,27 @@ bloom transcript AAPL "AI" "services" "margins" --max 20 -o /tmp/bloom/transcrip
|
|
|
115
117
|
jq '.matches[] | {speaker, text}' /tmp/bloom/transcript.json
|
|
116
118
|
```
|
|
117
119
|
|
|
120
|
+
### AI Arena (InvestingArena — 3 AIs with real money)
|
|
121
|
+
```bash
|
|
122
|
+
# All AI models' recent trades
|
|
123
|
+
bloom ai-trades -o /tmp/bloom/ai-trades.json
|
|
124
|
+
|
|
125
|
+
# Claude's last 5 trades
|
|
126
|
+
bloom ai-trades --model claude --limit 5
|
|
127
|
+
|
|
128
|
+
# All trades on NVDA across all models
|
|
129
|
+
bloom ai-trades --symbol NVDA -o /tmp/bloom/nvda-ai-trades.json
|
|
130
|
+
|
|
131
|
+
# Full portfolio snapshot for all 3 models
|
|
132
|
+
bloom ai-portfolio -o /tmp/bloom/ai-portfolio.json
|
|
133
|
+
|
|
134
|
+
# Just Gemini's portfolio
|
|
135
|
+
bloom ai-portfolio --model gemini
|
|
136
|
+
|
|
137
|
+
# Extract model returns
|
|
138
|
+
jq '[.[] | {model: .ai_model, return_pct, account_value}]' /tmp/bloom/ai-portfolio.json
|
|
139
|
+
```
|
|
140
|
+
|
|
118
141
|
## Tips
|
|
119
142
|
|
|
120
143
|
- Use `-o` to download data to files, then `jq` to extract. Saves context tokens.
|
package/SKILL.md
CHANGED
|
@@ -48,6 +48,8 @@ jq '.data[] | select(.revenue_growth > 0.1)' /tmp/bloom/aapl-revenue.json
|
|
|
48
48
|
| `catalysts` | Forward-looking value drivers | `bloom catalysts AAPL MSFT` |
|
|
49
49
|
| `position-size` | Kelly criterion sizing | `bloom position-size --bull 0.6 --bear -0.15 --conviction 8 --value 100000` |
|
|
50
50
|
| `transcript` | Search earnings call transcripts | `bloom transcript AAPL "AI" "services"` |
|
|
51
|
+
| `ai-trades` | Recent AI model trade decisions (InvestingArena) | `bloom ai-trades --model claude --limit 5` |
|
|
52
|
+
| `ai-portfolio` | AI model portfolio positions & performance | `bloom ai-portfolio --model openai` |
|
|
51
53
|
|
|
52
54
|
## Global Flags
|
|
53
55
|
|
|
@@ -111,6 +113,27 @@ bloom transcript AAPL "AI" "services" "margins" --max 20 -o /tmp/bloom/transcrip
|
|
|
111
113
|
jq '.matches[] | {speaker, text}' /tmp/bloom/transcript.json
|
|
112
114
|
```
|
|
113
115
|
|
|
116
|
+
### AI Arena (InvestingArena — 3 AIs with real money)
|
|
117
|
+
```bash
|
|
118
|
+
# All AI models' recent trades
|
|
119
|
+
bloom ai-trades -o /tmp/bloom/ai-trades.json
|
|
120
|
+
|
|
121
|
+
# Claude's last 5 trades
|
|
122
|
+
bloom ai-trades --model claude --limit 5
|
|
123
|
+
|
|
124
|
+
# All trades on NVDA across all models
|
|
125
|
+
bloom ai-trades --symbol NVDA -o /tmp/bloom/nvda-ai-trades.json
|
|
126
|
+
|
|
127
|
+
# Full portfolio snapshot for all 3 models
|
|
128
|
+
bloom ai-portfolio -o /tmp/bloom/ai-portfolio.json
|
|
129
|
+
|
|
130
|
+
# Just Gemini's portfolio
|
|
131
|
+
bloom ai-portfolio --model gemini
|
|
132
|
+
|
|
133
|
+
# Extract model returns
|
|
134
|
+
jq '[.[] | {model: .ai_model, return_pct, account_value}]' /tmp/bloom/ai-portfolio.json
|
|
135
|
+
```
|
|
136
|
+
|
|
114
137
|
## Tips
|
|
115
138
|
|
|
116
139
|
- Use `-o` to download data to files, then `jq` to extract. Saves context tokens.
|
package/dist/index.js
CHANGED
|
@@ -782,12 +782,138 @@ function formatTranscript(data, opts) {
|
|
|
782
782
|
return makeTable(["Speaker", "Role", "Text"], rows, opts);
|
|
783
783
|
}
|
|
784
784
|
|
|
785
|
+
// src/commands/ai-trades.ts
|
|
786
|
+
function registerAiTradesCommand(program2) {
|
|
787
|
+
addGlobalOptions(
|
|
788
|
+
program2.command("ai-trades").description("Recent trade decisions from AI models competing with real money (InvestingArena)").option("--model <m>", "Filter by AI model: claude|openai|gemini").option("--symbol <s>", "Filter by stock ticker symbol (e.g., AAPL)").option("--limit <n>", "Max recent trades per model (default: 10, max: 50)", "10")
|
|
789
|
+
).action(async (opts) => {
|
|
790
|
+
const args = {
|
|
791
|
+
limit: parseIntSafe(opts.limit, 10)
|
|
792
|
+
};
|
|
793
|
+
if (opts.model) args.ai_model = opts.model;
|
|
794
|
+
if (opts.symbol) args.symbol = opts.symbol.toUpperCase();
|
|
795
|
+
const data = await callTool("get_ai_trade_ideas", args);
|
|
796
|
+
if (opts.raw) {
|
|
797
|
+
outputResult(data, opts);
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
const obj = data;
|
|
801
|
+
const trades = obj.recent_trades ?? data;
|
|
802
|
+
outputResult(trades, opts, (d, o) => formatTrades(d, o));
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
function formatTrades(data, opts) {
|
|
806
|
+
if (!data || !Array.isArray(data)) {
|
|
807
|
+
if (data && typeof data === "object") {
|
|
808
|
+
return JSON.stringify(data, null, 2);
|
|
809
|
+
}
|
|
810
|
+
return String(data ?? "(no trades)");
|
|
811
|
+
}
|
|
812
|
+
if (data.length === 0) return "(no trades found)";
|
|
813
|
+
const rows = data.map((trade) => {
|
|
814
|
+
const t = trade;
|
|
815
|
+
const gain = t.realized_gain_loss != null ? `$${Number(t.realized_gain_loss).toFixed(2)}` : "-";
|
|
816
|
+
return [
|
|
817
|
+
String(t.ai_model ?? t.model ?? "-"),
|
|
818
|
+
String(t.action ?? "-").toUpperCase(),
|
|
819
|
+
String(t.symbol ?? "-"),
|
|
820
|
+
String(t.shares ?? "-"),
|
|
821
|
+
t.fill_price != null ? `$${Number(t.fill_price).toFixed(2)}` : "-",
|
|
822
|
+
gain,
|
|
823
|
+
truncate2(String(t.rationale ?? "-"), 60)
|
|
824
|
+
];
|
|
825
|
+
});
|
|
826
|
+
return makeTable(
|
|
827
|
+
["Model", "Action", "Symbol", "Shares", "Fill Price", "Realized P/L", "Rationale"],
|
|
828
|
+
rows,
|
|
829
|
+
opts
|
|
830
|
+
);
|
|
831
|
+
}
|
|
832
|
+
function truncate2(s, max) {
|
|
833
|
+
return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// src/commands/ai-portfolio.ts
|
|
837
|
+
function registerAiPortfolioCommand(program2) {
|
|
838
|
+
addGlobalOptions(
|
|
839
|
+
program2.command("ai-portfolio").description("Current portfolio positions held by AI models (InvestingArena live accounts)").option("--model <m>", "Filter by AI model: claude|openai|gemini")
|
|
840
|
+
).action(async (opts) => {
|
|
841
|
+
const args = {};
|
|
842
|
+
if (opts.model) args.ai_model = opts.model;
|
|
843
|
+
const data = await callTool("get_ai_trade_ideas", args);
|
|
844
|
+
if (opts.raw) {
|
|
845
|
+
outputResult(data, opts);
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
const obj = data;
|
|
849
|
+
const portfolios = obj.portfolios ?? data;
|
|
850
|
+
outputResult(portfolios, opts, (d, o) => formatPortfolios(d, o));
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
function formatPortfolios(data, opts) {
|
|
854
|
+
if (!data || !Array.isArray(data)) {
|
|
855
|
+
if (data && typeof data === "object") {
|
|
856
|
+
return JSON.stringify(data, null, 2);
|
|
857
|
+
}
|
|
858
|
+
return String(data ?? "(no portfolio data)");
|
|
859
|
+
}
|
|
860
|
+
if (data.length === 0) return "(no portfolio data found)";
|
|
861
|
+
const lines = [];
|
|
862
|
+
for (const portfolio of data) {
|
|
863
|
+
const p = portfolio;
|
|
864
|
+
const modelName = String(p.ai_model ?? p.model ?? "Unknown").toUpperCase();
|
|
865
|
+
lines.push(`
|
|
866
|
+
=== ${modelName} ===`);
|
|
867
|
+
const acctValue = p.account_value != null ? `$${Number(p.account_value).toFixed(2)}` : "-";
|
|
868
|
+
const cash = p.cash != null ? `$${Number(p.cash).toFixed(2)}` : "-";
|
|
869
|
+
const returnPct = p.return_pct != null ? `${Number(p.return_pct).toFixed(2)}%` : "-";
|
|
870
|
+
const pnl = p.total_pnl != null ? `$${Number(p.total_pnl).toFixed(2)}` : "-";
|
|
871
|
+
lines.push(` Account Value: ${acctValue} | Cash: ${cash} | Return: ${returnPct} | Total P&L: ${pnl}`);
|
|
872
|
+
const positions = p.positions;
|
|
873
|
+
if (Array.isArray(positions) && positions.length > 0) {
|
|
874
|
+
lines.push("");
|
|
875
|
+
const rows = positions.map((pos) => {
|
|
876
|
+
const position = pos;
|
|
877
|
+
const unrealizedPnl = position.unrealized_pnl != null ? `$${Number(position.unrealized_pnl).toFixed(2)}` : "-";
|
|
878
|
+
const allocation = position.allocation_pct != null ? `${Number(position.allocation_pct).toFixed(1)}%` : "-";
|
|
879
|
+
const avgCost = position.avg_cost != null ? `$${Number(position.avg_cost).toFixed(2)}` : "-";
|
|
880
|
+
return [
|
|
881
|
+
String(position.symbol ?? "-"),
|
|
882
|
+
String(position.qty ?? "-"),
|
|
883
|
+
avgCost,
|
|
884
|
+
unrealizedPnl,
|
|
885
|
+
allocation
|
|
886
|
+
];
|
|
887
|
+
});
|
|
888
|
+
lines.push(
|
|
889
|
+
makeTable(["Symbol", "Qty", "Avg Cost", "Unrealized P/L", "Allocation"], rows, opts)
|
|
890
|
+
);
|
|
891
|
+
} else {
|
|
892
|
+
lines.push(" (no open positions)");
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
return lines.join("\n");
|
|
896
|
+
}
|
|
897
|
+
|
|
785
898
|
// src/index.ts
|
|
786
899
|
var program = new Command();
|
|
787
900
|
var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
788
901
|
var pkgPath = path.join(__dirname, "..", "package.json");
|
|
789
|
-
var
|
|
790
|
-
|
|
902
|
+
var compiledVersion = "0.1.3".length > 0 ? "0.1.3" : void 0;
|
|
903
|
+
var envVersion = process.env.BLOOM_CLI_VERSION ?? process.env.npm_package_version;
|
|
904
|
+
var fallbackVersion = compiledVersion ?? "unknown";
|
|
905
|
+
var cliVersion = envVersion ?? fallbackVersion;
|
|
906
|
+
try {
|
|
907
|
+
const pkg = JSON.parse(readFileSync2(pkgPath, "utf8"));
|
|
908
|
+
if (typeof pkg.version === "string") {
|
|
909
|
+
cliVersion = pkg.version;
|
|
910
|
+
}
|
|
911
|
+
} catch {
|
|
912
|
+
}
|
|
913
|
+
if (cliVersion === "0.0.0") {
|
|
914
|
+
cliVersion = fallbackVersion;
|
|
915
|
+
}
|
|
916
|
+
program.name("bloom").description("Bloom CLI \u2014 financial data for coding agents and humans").version(cliVersion);
|
|
791
917
|
registerAuthCommand(program);
|
|
792
918
|
registerInfoCommand(program);
|
|
793
919
|
registerNewsCommand(program);
|
|
@@ -805,6 +931,8 @@ registerTradesCommand(program);
|
|
|
805
931
|
registerCatalystsCommand(program);
|
|
806
932
|
registerPositionCommand(program);
|
|
807
933
|
registerTranscriptCommand(program);
|
|
934
|
+
registerAiTradesCommand(program);
|
|
935
|
+
registerAiPortfolioCommand(program);
|
|
808
936
|
program.parseAsync().catch((err) => {
|
|
809
937
|
console.error("Error:", err.message || err);
|
|
810
938
|
process.exit(1);
|