market-data-analyzer 2.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.
Potentially problematic release.
This version of market-data-analyzer might be problematic. Click here for more details.
- package/README.md +159 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +267 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/analyze_portfolio.d.ts +14 -0
- package/dist/tools/analyze_portfolio.d.ts.map +1 -0
- package/dist/tools/analyze_portfolio.js +155 -0
- package/dist/tools/analyze_portfolio.js.map +1 -0
- package/dist/tools/analyze_stock.d.ts +8 -0
- package/dist/tools/analyze_stock.d.ts.map +1 -0
- package/dist/tools/analyze_stock.js +211 -0
- package/dist/tools/analyze_stock.js.map +1 -0
- package/dist/tools/compare_assets.d.ts +8 -0
- package/dist/tools/compare_assets.d.ts.map +1 -0
- package/dist/tools/compare_assets.js +138 -0
- package/dist/tools/compare_assets.js.map +1 -0
- package/dist/tools/crypto_analysis.d.ts +8 -0
- package/dist/tools/crypto_analysis.d.ts.map +1 -0
- package/dist/tools/crypto_analysis.js +192 -0
- package/dist/tools/crypto_analysis.js.map +1 -0
- package/dist/tools/market_overview.d.ts +8 -0
- package/dist/tools/market_overview.d.ts.map +1 -0
- package/dist/tools/market_overview.js +223 -0
- package/dist/tools/market_overview.js.map +1 -0
- package/dist/tools/screen_stocks.d.ts +19 -0
- package/dist/tools/screen_stocks.d.ts.map +1 -0
- package/dist/tools/screen_stocks.js +122 -0
- package/dist/tools/screen_stocks.js.map +1 -0
- package/dist/types.d.ts +158 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/api.d.ts +37 -0
- package/dist/utils/api.d.ts.map +1 -0
- package/dist/utils/api.js +228 -0
- package/dist/utils/api.js.map +1 -0
- package/dist/utils/cache.d.ts +20 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +52 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/math.d.ts +30 -0
- package/dist/utils/math.d.ts.map +1 -0
- package/dist/utils/math.js +300 -0
- package/dist/utils/math.js.map +1 -0
- package/package.json +30 -0
- package/src/index.ts +329 -0
- package/src/tools/analyze_portfolio.ts +204 -0
- package/src/tools/analyze_stock.ts +204 -0
- package/src/tools/compare_assets.ts +181 -0
- package/src/tools/crypto_analysis.ts +221 -0
- package/src/tools/market_overview.ts +236 -0
- package/src/tools/screen_stocks.ts +154 -0
- package/src/types.ts +175 -0
- package/src/utils/api.ts +262 -0
- package/src/utils/cache.ts +65 -0
- package/src/utils/math.ts +332 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"math.js","sourceRoot":"","sources":["../../src/utils/math.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "market-data-analyzer",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "MCP server for financial market data analysis -- live stock analysis, screening, portfolio analytics, crypto analysis, and market overview using free APIs.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"market-data-analyzer": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"start:sse": "node dist/index.js --sse",
|
|
14
|
+
"dev": "tsc --watch",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"keywords": ["mcp", "finance", "stocks", "crypto", "technical-analysis", "portfolio", "market-data", "trading", "yahoo-finance", "coingecko"],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
21
|
+
"zod": "^3.25.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^22.0.0",
|
|
25
|
+
"typescript": "^5.7.0"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18.0.0"
|
|
29
|
+
}
|
|
30
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Market Data Analyzer -- MCP Server
|
|
5
|
+
*
|
|
6
|
+
* Finance-focused MCP server with live data from Yahoo Finance and CoinGecko.
|
|
7
|
+
* Tools: analyze_stock, screen_stocks, analyze_portfolio, compare_assets,
|
|
8
|
+
* market_overview, crypto_analysis.
|
|
9
|
+
*
|
|
10
|
+
* Transports: stdio (default) or SSE (--sse flag).
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
14
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
15
|
+
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
import http from "node:http";
|
|
18
|
+
|
|
19
|
+
import { handleAnalyzeStock } from "./tools/analyze_stock.js";
|
|
20
|
+
import { handleScreenStocks } from "./tools/screen_stocks.js";
|
|
21
|
+
import { handleAnalyzePortfolio } from "./tools/analyze_portfolio.js";
|
|
22
|
+
import { handleCompareAssets } from "./tools/compare_assets.js";
|
|
23
|
+
import { handleMarketOverview } from "./tools/market_overview.js";
|
|
24
|
+
import { handleCryptoAnalysis } from "./tools/crypto_analysis.js";
|
|
25
|
+
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Server setup
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
const server = new McpServer({
|
|
31
|
+
name: "market-data-analyzer",
|
|
32
|
+
version: "2.0.0",
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Tool: analyze_stock
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
server.tool(
|
|
40
|
+
"analyze_stock",
|
|
41
|
+
"Deep analysis of a stock symbol: price, moving averages (SMA 20/50/200), RSI, MACD, support/resistance levels. Uses live Yahoo Finance data.",
|
|
42
|
+
{
|
|
43
|
+
symbol: z
|
|
44
|
+
.string()
|
|
45
|
+
.describe("Stock ticker symbol (e.g. 'AAPL', 'MSFT', 'TSLA')"),
|
|
46
|
+
},
|
|
47
|
+
async ({ symbol }) => {
|
|
48
|
+
try {
|
|
49
|
+
const result = await handleAnalyzeStock(symbol.toUpperCase());
|
|
50
|
+
return { content: [{ type: "text" as const, text: result }] };
|
|
51
|
+
} catch (err) {
|
|
52
|
+
return {
|
|
53
|
+
content: [
|
|
54
|
+
{
|
|
55
|
+
type: "text" as const,
|
|
56
|
+
text: `Error analyzing ${symbol}: ${err instanceof Error ? err.message : String(err)}`,
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
isError: true,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// Tool: screen_stocks
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
server.tool(
|
|
70
|
+
"screen_stocks",
|
|
71
|
+
"Screen stocks by criteria: market cap range, P/E ratio, sector, volume threshold. Returns top matches with key metrics. Fetches live data from Yahoo Finance for ~70 popular stocks.",
|
|
72
|
+
{
|
|
73
|
+
min_market_cap: z
|
|
74
|
+
.number()
|
|
75
|
+
.optional()
|
|
76
|
+
.describe("Minimum market cap in USD (e.g. 1000000000 for $1B)"),
|
|
77
|
+
max_market_cap: z.number().optional().describe("Maximum market cap in USD"),
|
|
78
|
+
min_pe: z.number().optional().describe("Minimum trailing P/E ratio"),
|
|
79
|
+
max_pe: z.number().optional().describe("Maximum trailing P/E ratio"),
|
|
80
|
+
sector: z
|
|
81
|
+
.string()
|
|
82
|
+
.optional()
|
|
83
|
+
.describe("Sector filter (partial match, e.g. 'tech', 'health', 'energy')"),
|
|
84
|
+
min_volume: z.number().optional().describe("Minimum daily trading volume"),
|
|
85
|
+
min_price: z.number().optional().describe("Minimum stock price"),
|
|
86
|
+
max_price: z.number().optional().describe("Maximum stock price"),
|
|
87
|
+
limit: z
|
|
88
|
+
.number()
|
|
89
|
+
.int()
|
|
90
|
+
.min(1)
|
|
91
|
+
.max(50)
|
|
92
|
+
.optional()
|
|
93
|
+
.describe("Max results to return (default: 25)"),
|
|
94
|
+
},
|
|
95
|
+
async (criteria) => {
|
|
96
|
+
try {
|
|
97
|
+
const result = await handleScreenStocks(criteria);
|
|
98
|
+
return { content: [{ type: "text" as const, text: result }] };
|
|
99
|
+
} catch (err) {
|
|
100
|
+
return {
|
|
101
|
+
content: [
|
|
102
|
+
{
|
|
103
|
+
type: "text" as const,
|
|
104
|
+
text: `Error screening stocks: ${err instanceof Error ? err.message : String(err)}`,
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
isError: true,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
// Tool: analyze_portfolio
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
server.tool(
|
|
118
|
+
"analyze_portfolio",
|
|
119
|
+
"Analyze a portfolio of holdings. Provide positions with symbol, shares, and average cost. Returns total value, P&L per position, allocation %, diversification score, and risk metrics. Fetches live prices from Yahoo Finance.",
|
|
120
|
+
{
|
|
121
|
+
holdings: z
|
|
122
|
+
.array(
|
|
123
|
+
z.object({
|
|
124
|
+
symbol: z.string().describe("Ticker symbol (e.g. 'AAPL')"),
|
|
125
|
+
shares: z.number().describe("Number of shares held"),
|
|
126
|
+
avg_cost: z.number().describe("Average cost per share"),
|
|
127
|
+
}),
|
|
128
|
+
)
|
|
129
|
+
.min(1)
|
|
130
|
+
.describe("Array of portfolio holdings"),
|
|
131
|
+
},
|
|
132
|
+
async ({ holdings }) => {
|
|
133
|
+
try {
|
|
134
|
+
const result = await handleAnalyzePortfolio(holdings);
|
|
135
|
+
return { content: [{ type: "text" as const, text: result }] };
|
|
136
|
+
} catch (err) {
|
|
137
|
+
return {
|
|
138
|
+
content: [
|
|
139
|
+
{
|
|
140
|
+
type: "text" as const,
|
|
141
|
+
text: `Error analyzing portfolio: ${err instanceof Error ? err.message : String(err)}`,
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
isError: true,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
// Tool: compare_assets
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
|
|
154
|
+
server.tool(
|
|
155
|
+
"compare_assets",
|
|
156
|
+
"Compare 2-5 assets side by side: returns, volatility, correlation, Sharpe ratio approximation over a given period. Uses Yahoo Finance historical data.",
|
|
157
|
+
{
|
|
158
|
+
symbols: z
|
|
159
|
+
.array(z.string())
|
|
160
|
+
.min(2)
|
|
161
|
+
.max(5)
|
|
162
|
+
.describe("Array of 2-5 ticker symbols to compare (e.g. ['AAPL', 'MSFT', 'GOOGL'])"),
|
|
163
|
+
period: z
|
|
164
|
+
.enum(["1mo", "3mo", "6mo", "1y", "2y", "5y"])
|
|
165
|
+
.optional()
|
|
166
|
+
.describe("Comparison period (default: '6mo')"),
|
|
167
|
+
},
|
|
168
|
+
async ({ symbols, period }) => {
|
|
169
|
+
try {
|
|
170
|
+
const result = await handleCompareAssets(
|
|
171
|
+
symbols.map((s) => s.toUpperCase()),
|
|
172
|
+
period ?? "6mo",
|
|
173
|
+
);
|
|
174
|
+
return { content: [{ type: "text" as const, text: result }] };
|
|
175
|
+
} catch (err) {
|
|
176
|
+
return {
|
|
177
|
+
content: [
|
|
178
|
+
{
|
|
179
|
+
type: "text" as const,
|
|
180
|
+
text: `Error comparing assets: ${err instanceof Error ? err.message : String(err)}`,
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
isError: true,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
// ---------------------------------------------------------------------------
|
|
190
|
+
// Tool: market_overview
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
|
|
193
|
+
server.tool(
|
|
194
|
+
"market_overview",
|
|
195
|
+
"Current market snapshot: major indices (S&P 500, NASDAQ, DOW), sector performance via ETFs, market breadth indicators, VIX, crypto, and commodities. Live data from Yahoo Finance.",
|
|
196
|
+
{},
|
|
197
|
+
async () => {
|
|
198
|
+
try {
|
|
199
|
+
const result = await handleMarketOverview();
|
|
200
|
+
return { content: [{ type: "text" as const, text: result }] };
|
|
201
|
+
} catch (err) {
|
|
202
|
+
return {
|
|
203
|
+
content: [
|
|
204
|
+
{
|
|
205
|
+
type: "text" as const,
|
|
206
|
+
text: `Error fetching market overview: ${err instanceof Error ? err.message : String(err)}`,
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
isError: true,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
// ---------------------------------------------------------------------------
|
|
216
|
+
// Tool: crypto_analysis
|
|
217
|
+
// ---------------------------------------------------------------------------
|
|
218
|
+
|
|
219
|
+
server.tool(
|
|
220
|
+
"crypto_analysis",
|
|
221
|
+
"Crypto-specific analysis: price, 24h volume, market dominance, fear/greed index approximation, supply metrics, ATH/ATL data. Uses CoinGecko free API.",
|
|
222
|
+
{
|
|
223
|
+
symbol: z
|
|
224
|
+
.string()
|
|
225
|
+
.describe("Cryptocurrency symbol or name (e.g. 'BTC', 'ETH', 'SOL', 'bitcoin')"),
|
|
226
|
+
},
|
|
227
|
+
async ({ symbol }) => {
|
|
228
|
+
try {
|
|
229
|
+
const result = await handleCryptoAnalysis(symbol);
|
|
230
|
+
return { content: [{ type: "text" as const, text: result }] };
|
|
231
|
+
} catch (err) {
|
|
232
|
+
return {
|
|
233
|
+
content: [
|
|
234
|
+
{
|
|
235
|
+
type: "text" as const,
|
|
236
|
+
text: `Error analyzing crypto ${symbol}: ${err instanceof Error ? err.message : String(err)}`,
|
|
237
|
+
},
|
|
238
|
+
],
|
|
239
|
+
isError: true,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
// ---------------------------------------------------------------------------
|
|
246
|
+
// Transport: stdio or SSE
|
|
247
|
+
// ---------------------------------------------------------------------------
|
|
248
|
+
|
|
249
|
+
async function main(): Promise<void> {
|
|
250
|
+
const useSSE = process.argv.includes("--sse");
|
|
251
|
+
|
|
252
|
+
if (useSSE) {
|
|
253
|
+
const port = parseInt(process.env.PORT ?? "3000", 10);
|
|
254
|
+
const transports = new Map<string, SSEServerTransport>();
|
|
255
|
+
|
|
256
|
+
const httpServer = http.createServer(async (req, res) => {
|
|
257
|
+
// CORS headers
|
|
258
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
259
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
260
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
261
|
+
|
|
262
|
+
if (req.method === "OPTIONS") {
|
|
263
|
+
res.writeHead(204);
|
|
264
|
+
res.end();
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
269
|
+
|
|
270
|
+
if (url.pathname === "/sse" && req.method === "GET") {
|
|
271
|
+
const transport = new SSEServerTransport("/messages", res);
|
|
272
|
+
const sessionId = transport.sessionId;
|
|
273
|
+
transports.set(sessionId, transport);
|
|
274
|
+
|
|
275
|
+
res.on("close", () => {
|
|
276
|
+
transports.delete(sessionId);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
await server.connect(transport);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (url.pathname === "/messages" && req.method === "POST") {
|
|
284
|
+
const sessionId = url.searchParams.get("sessionId");
|
|
285
|
+
if (!sessionId || !transports.has(sessionId)) {
|
|
286
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
287
|
+
res.end(JSON.stringify({ error: "Invalid or missing sessionId" }));
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const transport = transports.get(sessionId)!;
|
|
291
|
+
await transport.handlePostMessage(req, res);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (url.pathname === "/health") {
|
|
296
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
297
|
+
res.end(
|
|
298
|
+
JSON.stringify({
|
|
299
|
+
status: "ok",
|
|
300
|
+
server: "market-data-analyzer",
|
|
301
|
+
version: "2.0.0",
|
|
302
|
+
}),
|
|
303
|
+
);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
308
|
+
res.end(JSON.stringify({ error: "Not found" }));
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
httpServer.listen(port, () => {
|
|
312
|
+
console.error(
|
|
313
|
+
`Market Data Analyzer MCP server (SSE) listening on port ${port}`,
|
|
314
|
+
);
|
|
315
|
+
console.error(` SSE endpoint: http://localhost:${port}/sse`);
|
|
316
|
+
console.error(` Messages endpoint: http://localhost:${port}/messages`);
|
|
317
|
+
console.error(` Health check: http://localhost:${port}/health`);
|
|
318
|
+
});
|
|
319
|
+
} else {
|
|
320
|
+
const transport = new StdioServerTransport();
|
|
321
|
+
await server.connect(transport);
|
|
322
|
+
console.error("Market Data Analyzer MCP server running on stdio");
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
main().catch((err) => {
|
|
327
|
+
console.error("Fatal error:", err);
|
|
328
|
+
process.exit(1);
|
|
329
|
+
});
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* analyze_portfolio -- Portfolio analytics with live prices.
|
|
3
|
+
*
|
|
4
|
+
* Takes an array of { symbol, shares, avg_cost } holdings, fetches
|
|
5
|
+
* current prices from Yahoo Finance, and returns P&L, allocation,
|
|
6
|
+
* diversification score, and risk metrics.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { yahooQuote } from "../utils/api.js";
|
|
10
|
+
import { formatCurrency } from "../utils/math.js";
|
|
11
|
+
|
|
12
|
+
export interface PortfolioHolding {
|
|
13
|
+
symbol: string;
|
|
14
|
+
shares: number;
|
|
15
|
+
avg_cost: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface PositionResult {
|
|
19
|
+
symbol: string;
|
|
20
|
+
name: string;
|
|
21
|
+
shares: number;
|
|
22
|
+
avgCost: number;
|
|
23
|
+
currentPrice: number;
|
|
24
|
+
marketValue: number;
|
|
25
|
+
costBasis: number;
|
|
26
|
+
pnl: number;
|
|
27
|
+
pnlPercent: number;
|
|
28
|
+
allocationPercent: number;
|
|
29
|
+
sector: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function handleAnalyzePortfolio(
|
|
33
|
+
holdings: PortfolioHolding[],
|
|
34
|
+
): Promise<string> {
|
|
35
|
+
if (holdings.length === 0) {
|
|
36
|
+
throw new Error("At least one holding is required.");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Fetch live quotes for all symbols
|
|
40
|
+
const symbols = holdings.map((h) => h.symbol);
|
|
41
|
+
const quotes = await yahooQuote(symbols);
|
|
42
|
+
const quoteMap = new Map(quotes.map((q) => [q.symbol, q]));
|
|
43
|
+
|
|
44
|
+
// Build position analysis
|
|
45
|
+
let totalValue = 0;
|
|
46
|
+
let totalCost = 0;
|
|
47
|
+
|
|
48
|
+
const positions: PositionResult[] = holdings.map((h) => {
|
|
49
|
+
const q = quoteMap.get(h.symbol);
|
|
50
|
+
const currentPrice = q?.regularMarketPrice ?? 0;
|
|
51
|
+
const marketValue = h.shares * currentPrice;
|
|
52
|
+
const costBasis = h.shares * h.avg_cost;
|
|
53
|
+
totalValue += marketValue;
|
|
54
|
+
totalCost += costBasis;
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
symbol: h.symbol,
|
|
58
|
+
name: q?.shortName ?? q?.longName ?? h.symbol,
|
|
59
|
+
shares: h.shares,
|
|
60
|
+
avgCost: h.avg_cost,
|
|
61
|
+
currentPrice,
|
|
62
|
+
marketValue,
|
|
63
|
+
costBasis,
|
|
64
|
+
pnl: marketValue - costBasis,
|
|
65
|
+
pnlPercent: costBasis > 0 ? ((marketValue - costBasis) / costBasis) * 100 : 0,
|
|
66
|
+
allocationPercent: 0, // calculated below
|
|
67
|
+
sector: q?.sector ?? "Unknown",
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Calculate allocation percentages
|
|
72
|
+
for (const p of positions) {
|
|
73
|
+
p.allocationPercent = totalValue > 0 ? (p.marketValue / totalValue) * 100 : 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Sort by market value descending
|
|
77
|
+
positions.sort((a, b) => b.marketValue - a.marketValue);
|
|
78
|
+
|
|
79
|
+
// Sector breakdown
|
|
80
|
+
const sectorAlloc: Record<string, number> = {};
|
|
81
|
+
for (const p of positions) {
|
|
82
|
+
sectorAlloc[p.sector] = (sectorAlloc[p.sector] ?? 0) + p.allocationPercent;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Diversification score (HHI-based, 0-100 where 100 = perfectly diversified)
|
|
86
|
+
const weights = positions.map((p) => p.allocationPercent / 100);
|
|
87
|
+
const hhi = weights.reduce((s, w) => s + w * w, 0);
|
|
88
|
+
const n = weights.length;
|
|
89
|
+
const minHHI = n > 0 ? 1 / n : 1;
|
|
90
|
+
const divScore = n <= 1 ? 0 : Math.round((1 - (hhi - minHHI) / (1 - minHHI)) * 100);
|
|
91
|
+
|
|
92
|
+
// Risk warnings
|
|
93
|
+
const warnings: string[] = [];
|
|
94
|
+
|
|
95
|
+
for (const p of positions) {
|
|
96
|
+
if (p.allocationPercent > 30) {
|
|
97
|
+
warnings.push(`HIGH CONCENTRATION: ${p.symbol} is ${p.allocationPercent.toFixed(1)}% of portfolio.`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
for (const [sector, pct] of Object.entries(sectorAlloc)) {
|
|
102
|
+
if (pct > 50) {
|
|
103
|
+
warnings.push(`SECTOR RISK: ${sector} represents ${pct.toFixed(1)}% of portfolio.`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
for (const p of positions) {
|
|
108
|
+
if (p.pnlPercent < -20) {
|
|
109
|
+
warnings.push(`SIGNIFICANT LOSS: ${p.symbol} is down ${Math.abs(p.pnlPercent).toFixed(1)}%.`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (n < 5) {
|
|
114
|
+
warnings.push(`LOW DIVERSIFICATION: Only ${n} position(s). Consider adding more holdings.`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (Object.keys(sectorAlloc).length < 3 && n >= 3) {
|
|
118
|
+
warnings.push("LIMITED SECTOR EXPOSURE: Portfolio spans fewer than 3 sectors.");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Any positions where we couldn't fetch a price?
|
|
122
|
+
const missingPrices = positions.filter((p) => p.currentPrice === 0);
|
|
123
|
+
for (const p of missingPrices) {
|
|
124
|
+
warnings.push(`MISSING DATA: Could not fetch price for ${p.symbol}. Values may be inaccurate.`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Format output
|
|
128
|
+
const lines: string[] = [];
|
|
129
|
+
|
|
130
|
+
lines.push("# Portfolio Analysis");
|
|
131
|
+
lines.push("");
|
|
132
|
+
|
|
133
|
+
// Summary
|
|
134
|
+
lines.push("## Summary");
|
|
135
|
+
lines.push("");
|
|
136
|
+
lines.push("| Metric | Value |");
|
|
137
|
+
lines.push("|--------|-------|");
|
|
138
|
+
lines.push(`| Total Value | ${formatCurrency(totalValue)} |`);
|
|
139
|
+
lines.push(`| Total Cost Basis | ${formatCurrency(totalCost)} |`);
|
|
140
|
+
const totalPnl = totalValue - totalCost;
|
|
141
|
+
const totalPnlPct = totalCost > 0 ? ((totalPnl) / totalCost) * 100 : 0;
|
|
142
|
+
lines.push(`| Total P&L | ${totalPnl >= 0 ? "+" : ""}${formatCurrency(totalPnl)} (${totalPnlPct >= 0 ? "+" : ""}${totalPnlPct.toFixed(2)}%) |`);
|
|
143
|
+
lines.push(`| Positions | ${n} |`);
|
|
144
|
+
lines.push(`| Sectors | ${Object.keys(sectorAlloc).length} |`);
|
|
145
|
+
lines.push(`| Diversification Score | ${divScore}/100 |`);
|
|
146
|
+
lines.push("");
|
|
147
|
+
|
|
148
|
+
// Positions
|
|
149
|
+
lines.push("## Positions");
|
|
150
|
+
lines.push("");
|
|
151
|
+
lines.push("| Symbol | Name | Shares | Avg Cost | Price | Value | P&L | P&L% | Alloc% |");
|
|
152
|
+
lines.push("|--------|------|--------|----------|-------|-------|-----|------|--------|");
|
|
153
|
+
|
|
154
|
+
for (const p of positions) {
|
|
155
|
+
const pnlSign = p.pnl >= 0 ? "+" : "";
|
|
156
|
+
lines.push(
|
|
157
|
+
`| ${p.symbol} | ${p.name.slice(0, 20)} | ${p.shares} | $${p.avgCost.toFixed(2)} | $${p.currentPrice.toFixed(2)} | ${formatCurrency(p.marketValue)} | ${pnlSign}${formatCurrency(p.pnl)} | ${pnlSign}${p.pnlPercent.toFixed(2)}% | ${p.allocationPercent.toFixed(1)}% |`,
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
lines.push("");
|
|
161
|
+
|
|
162
|
+
// Sector allocation
|
|
163
|
+
lines.push("## Sector Allocation");
|
|
164
|
+
lines.push("");
|
|
165
|
+
lines.push("| Sector | Allocation |");
|
|
166
|
+
lines.push("|--------|------------|");
|
|
167
|
+
const sortedSectors = Object.entries(sectorAlloc).sort((a, b) => b[1] - a[1]);
|
|
168
|
+
for (const [sector, pct] of sortedSectors) {
|
|
169
|
+
const bar = "=".repeat(Math.round(pct / 2));
|
|
170
|
+
lines.push(`| ${sector} | ${pct.toFixed(1)}% ${bar} |`);
|
|
171
|
+
}
|
|
172
|
+
lines.push("");
|
|
173
|
+
|
|
174
|
+
// Winners and losers
|
|
175
|
+
const winners = [...positions].sort((a, b) => b.pnlPercent - a.pnlPercent);
|
|
176
|
+
if (winners.length > 0) {
|
|
177
|
+
lines.push("## Top Performers");
|
|
178
|
+
lines.push("");
|
|
179
|
+
const top3 = winners.slice(0, Math.min(3, winners.length));
|
|
180
|
+
for (const p of top3) {
|
|
181
|
+
lines.push(`- **${p.symbol}**: ${p.pnlPercent >= 0 ? "+" : ""}${p.pnlPercent.toFixed(2)}% (${p.pnl >= 0 ? "+" : ""}${formatCurrency(p.pnl)})`);
|
|
182
|
+
}
|
|
183
|
+
lines.push("");
|
|
184
|
+
const bottom3 = winners.slice(-Math.min(3, winners.length)).reverse();
|
|
185
|
+
lines.push("## Underperformers");
|
|
186
|
+
lines.push("");
|
|
187
|
+
for (const p of bottom3) {
|
|
188
|
+
lines.push(`- **${p.symbol}**: ${p.pnlPercent >= 0 ? "+" : ""}${p.pnlPercent.toFixed(2)}% (${p.pnl >= 0 ? "+" : ""}${formatCurrency(p.pnl)})`);
|
|
189
|
+
}
|
|
190
|
+
lines.push("");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Risk warnings
|
|
194
|
+
if (warnings.length > 0) {
|
|
195
|
+
lines.push("## Risk Warnings");
|
|
196
|
+
lines.push("");
|
|
197
|
+
for (const w of warnings) {
|
|
198
|
+
lines.push(`- ${w}`);
|
|
199
|
+
}
|
|
200
|
+
lines.push("");
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return lines.join("\n");
|
|
204
|
+
}
|