market-feed 0.1.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/CHANGELOG.md ADDED
@@ -0,0 +1,28 @@
1
+ # market-feed Changelog
2
+
3
+ ## 0.1.0 — 2026-03-10
4
+
5
+ ### Initial release
6
+
7
+ **Providers**
8
+ - `YahooProvider` — Yahoo Finance (no API key required): quote, historical, search, company
9
+ - `AlphaVantageProvider` — Alpha Vantage (free: 25/day): quote, historical, search, company
10
+ - `PolygonProvider` — Polygon.io (free: 15-min delayed): quote, historical, search, company, news
11
+
12
+ **Core**
13
+ - Unified `Quote`, `HistoricalBar`, `CompanyProfile`, `NewsItem`, `SearchResult`, `MarketStatus` types
14
+ - `MarketFeed` client with provider chain, automatic fallback, and LRU caching
15
+ - `MemoryCacheDriver` — zero-dependency LRU cache with TTL and configurable max size
16
+ - `CacheDriver` interface for plugging in Redis, Upstash, Cloudflare KV, or any store
17
+ - `RateLimiter` — token-bucket rate limiter (used internally; also exported for custom providers)
18
+ - `HttpClient` — fetch wrapper with exponential-backoff retry and per-request timeout
19
+ - Symbol utilities: `normalise`, `stripExchange`, `toYahooSymbol`, `toAlphaVantageSymbol`, `toPolygonSymbol`, `dedupeSymbols`
20
+ - Error hierarchy: `MarketFeedError`, `ProviderError`, `RateLimitError`, `UnsupportedOperationError`, `AllProvidersFailedError`
21
+
22
+ **DX**
23
+ - Zero production dependencies (native `fetch` only)
24
+ - Strict TypeScript — `strict: true`, `noUncheckedIndexedAccess`, `noImplicitOverride`
25
+ - ESM + CJS + `.d.ts` dual build
26
+ - Multi-runtime: Node 18+, Bun 1+, Deno 2+, Cloudflare Workers
27
+ - 80+ unit tests covering all providers, cache, rate limiter, symbol utils, and error classes
28
+ - VitePress documentation site
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 market-feed contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,332 @@
1
+ # market-feed
2
+
3
+ > Unified TypeScript client for financial market data.
4
+ > Wraps Yahoo Finance, Alpha Vantage, and Polygon.io under one consistent interface — with caching and automatic fallback built in.
5
+
6
+ [![CI](https://github.com/piyushgupta344/market-feed/actions/workflows/ci.yml/badge.svg)](https://github.com/piyushgupta344/market-feed/actions/workflows/ci.yml)
7
+ [![npm version](https://badge.fury.io/js/market-feed.svg)](https://www.npmjs.com/package/market-feed)
8
+ [![npm downloads](https://img.shields.io/npm/dm/market-feed)](https://www.npmjs.com/package/market-feed)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
10
+ [![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue.svg)](tsconfig.json)
11
+
12
+ ---
13
+
14
+ ## The problem
15
+
16
+ Every free financial API speaks a different language:
17
+
18
+ ```ts
19
+ // Yahoo Finance
20
+ result.chart.result[0].meta.regularMarketPrice
21
+
22
+ // Alpha Vantage
23
+ data["Global Quote"]["05. price"]
24
+
25
+ // Polygon.io
26
+ data.ticker.lastTrade.p
27
+ ```
28
+
29
+ You write adapters, you add caching, you handle fallback — for every project, every time.
30
+
31
+ ## The solution
32
+
33
+ ```ts
34
+ import { MarketFeed } from "market-feed";
35
+
36
+ const feed = new MarketFeed();
37
+ const quote = await feed.quote("AAPL");
38
+
39
+ console.log(quote.price); // always a number, always the same key
40
+ ```
41
+
42
+ One interface. Three providers. Zero API key required for Yahoo Finance.
43
+
44
+ ---
45
+
46
+ ## Features
47
+
48
+ - **Unified types** — `Quote`, `HistoricalBar`, `CompanyProfile`, `NewsItem`, `SearchResult` are consistent regardless of which provider answers
49
+ - **Zero production dependencies** — uses native `fetch`, works everywhere
50
+ - **Built-in LRU cache** — configurable TTL per method, pluggable driver (Redis, Upstash, etc.)
51
+ - **Automatic fallback** — if Yahoo is down, tries Alpha Vantage, then Polygon
52
+ - **Rate-limit aware** — won't silently burn your free Alpha Vantage / Polygon quota
53
+ - **Strict TypeScript** — no `any`, full autocomplete, compile-time safety
54
+ - **Multi-runtime** — Node 18+, Bun 1+, Deno 2+, Cloudflare Workers
55
+ - **Escape hatch** — pass `{ raw: true }` to get the original provider response
56
+
57
+ ---
58
+
59
+ ## Install
60
+
61
+ ```bash
62
+ npm install market-feed
63
+ # or
64
+ pnpm add market-feed
65
+ # or
66
+ bun add market-feed
67
+ ```
68
+
69
+ ---
70
+
71
+ ## Quick Start
72
+
73
+ ```ts
74
+ import { MarketFeed } from "market-feed";
75
+
76
+ // Zero-config — uses Yahoo Finance, no API key needed
77
+ const feed = new MarketFeed();
78
+
79
+ // Single quote
80
+ const aapl = await feed.quote("AAPL");
81
+ console.log(`${aapl.symbol}: $${aapl.price.toFixed(2)}`);
82
+
83
+ // Multiple quotes (parallel)
84
+ const quotes = await feed.quote(["MSFT", "GOOGL", "AMZN"]);
85
+
86
+ // Historical data
87
+ const history = await feed.historical("AAPL", {
88
+ period1: "2024-01-01",
89
+ period2: "2024-12-31",
90
+ interval: "1d",
91
+ });
92
+
93
+ // Search
94
+ const results = await feed.search("Tesla");
95
+
96
+ // Company profile
97
+ const profile = await feed.company("AAPL");
98
+ console.log(profile.sector); // "Technology"
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Providers
104
+
105
+ | Provider | API Key | Quote | Historical | Search | Company | News | Market Status |
106
+ |----------|---------|:-----:|:----------:|:------:|:-------:|:----:|:-------------:|
107
+ | **Yahoo Finance** | Not required | ✓ | ✓ | ✓ | ✓ | — | — |
108
+ | **Alpha Vantage** | Free (25/day) | ✓ | ✓ | ✓ | ✓ | — | — |
109
+ | **Polygon.io** | Free (delayed) | ✓ | ✓ | ✓ | ✓ | ✓ | — |
110
+
111
+ Get free keys: [Alpha Vantage](https://www.alphavantage.co/support/#api-key) · [Polygon.io](https://polygon.io/)
112
+
113
+ ### Using multiple providers
114
+
115
+ ```ts
116
+ import {
117
+ MarketFeed,
118
+ YahooProvider,
119
+ AlphaVantageProvider,
120
+ PolygonProvider,
121
+ } from "market-feed";
122
+
123
+ const feed = new MarketFeed({
124
+ providers: [
125
+ new YahooProvider(),
126
+ new AlphaVantageProvider({ apiKey: process.env.AV_KEY }),
127
+ new PolygonProvider({ apiKey: process.env.POLYGON_KEY }),
128
+ ],
129
+ fallback: true, // auto-try next provider on failure
130
+ });
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Caching
136
+
137
+ The default LRU cache stores responses in memory with sensible TTLs:
138
+
139
+ | Method | Default TTL |
140
+ |--------|-------------|
141
+ | `quote` | 60s |
142
+ | `historical` | 1 hour |
143
+ | `company` | 24 hours |
144
+ | `news` | 5 minutes |
145
+ | `search` | 10 minutes |
146
+ | `marketStatus` | 60s |
147
+
148
+ ### Override TTLs
149
+
150
+ ```ts
151
+ const feed = new MarketFeed({
152
+ cache: {
153
+ ttl: 60, // default fallback TTL
154
+ maxSize: 1000, // max entries in memory
155
+ ttlOverrides: {
156
+ quote: 15, // aggressive refresh for real-time feel
157
+ company: 604800, // company profiles change rarely
158
+ },
159
+ },
160
+ });
161
+ ```
162
+
163
+ ### Disable caching
164
+
165
+ ```ts
166
+ const feed = new MarketFeed({ cache: false });
167
+ ```
168
+
169
+ ### Custom cache driver (Redis, Upstash, filesystem...)
170
+
171
+ ```ts
172
+ import type { CacheDriver } from "market-feed";
173
+ import { createClient } from "redis";
174
+
175
+ const redis = createClient();
176
+ await redis.connect();
177
+
178
+ const driver: CacheDriver = {
179
+ async get<T>(key: string) {
180
+ const val = await redis.get(key);
181
+ return val ? (JSON.parse(val) as T) : undefined;
182
+ },
183
+ async set<T>(key: string, value: T, ttl = 60) {
184
+ await redis.set(key, JSON.stringify(value), { EX: ttl });
185
+ },
186
+ async delete(key: string) { await redis.del(key); },
187
+ async clear() { await redis.flushDb(); },
188
+ };
189
+
190
+ const feed = new MarketFeed({ cache: { driver } });
191
+ ```
192
+
193
+ ---
194
+
195
+ ## API Reference
196
+
197
+ ### `new MarketFeed(options?)`
198
+
199
+ | Option | Type | Default | Description |
200
+ |--------|------|---------|-------------|
201
+ | `providers` | `MarketProvider[]` | `[new YahooProvider()]` | Provider chain |
202
+ | `cache` | `CacheConfig \| false` | LRU, 60s TTL | Cache configuration |
203
+ | `fallback` | `boolean` | `true` | Auto-failover on provider error |
204
+
205
+ ### Methods
206
+
207
+ ```ts
208
+ // Quotes
209
+ feed.quote(symbol: string, options?: QuoteOptions): Promise<Quote>
210
+ feed.quote(symbols: string[], options?: QuoteOptions): Promise<Quote[]>
211
+
212
+ // Historical bars
213
+ feed.historical(symbol: string, options?: HistoricalOptions): Promise<HistoricalBar[]>
214
+
215
+ // Symbol search
216
+ feed.search(query: string, options?: SearchOptions): Promise<SearchResult[]>
217
+
218
+ // Company profile
219
+ feed.company(symbol: string, options?: CompanyOptions): Promise<CompanyProfile>
220
+
221
+ // News
222
+ feed.news(symbol: string, options?: NewsOptions): Promise<NewsItem[]>
223
+
224
+ // Market status
225
+ feed.marketStatus(market?: string): Promise<MarketStatus>
226
+
227
+ // Cache management
228
+ feed.clearCache(): Promise<void>
229
+ feed.invalidate(key: string): Promise<void>
230
+ ```
231
+
232
+ ### `HistoricalOptions`
233
+
234
+ ```ts
235
+ interface HistoricalOptions {
236
+ period1?: string | Date; // start date, default: 1 year ago
237
+ period2?: string | Date; // end date, default: today
238
+ interval?: "1m" | "2m" | "5m" | "15m" | "30m" | "60m" | "1h"
239
+ | "1d" | "5d" | "1wk" | "1mo" | "3mo"; // default: "1d"
240
+ raw?: boolean;
241
+ }
242
+ ```
243
+
244
+ ---
245
+
246
+ ## Error Handling
247
+
248
+ ```ts
249
+ import {
250
+ MarketFeedError,
251
+ ProviderError,
252
+ RateLimitError,
253
+ AllProvidersFailedError,
254
+ } from "market-feed";
255
+
256
+ try {
257
+ const quote = await feed.quote("AAPL");
258
+ } catch (err) {
259
+ if (err instanceof RateLimitError) {
260
+ console.log(`Rate limited. Retry after: ${err.retryAfter?.toISOString()}`);
261
+ } else if (err instanceof AllProvidersFailedError) {
262
+ console.log("All providers failed:", err.errors.map(e => e.message));
263
+ } else if (err instanceof ProviderError) {
264
+ console.log(`Provider error (${err.provider}): ${err.message}`);
265
+ }
266
+ }
267
+ ```
268
+
269
+ ---
270
+
271
+ ## Building a Custom Provider
272
+
273
+ Implement the `MarketProvider` interface to add any data source:
274
+
275
+ ```ts
276
+ import type { MarketProvider, Quote } from "market-feed";
277
+
278
+ class MyProvider implements MarketProvider {
279
+ readonly name = "my-provider";
280
+
281
+ async quote(symbols: string[]): Promise<Quote[]> {
282
+ // fetch from your API, return normalised Quote objects
283
+ }
284
+
285
+ async historical(symbol: string, options) {
286
+ // ...
287
+ }
288
+
289
+ async search(query: string) {
290
+ // ...
291
+ }
292
+ }
293
+
294
+ const feed = new MarketFeed({ providers: [new MyProvider()] });
295
+ ```
296
+
297
+ ---
298
+
299
+ ## Runtime Compatibility
300
+
301
+ | Runtime | Version | Notes |
302
+ |---------|---------|-------|
303
+ | Node.js | 18+ | Requires native `fetch` (available since Node 18) |
304
+ | Bun | 1+ | Fully supported |
305
+ | Deno | 2+ | Fully supported |
306
+ | Cloudflare Workers | Latest | Fully supported |
307
+ | Browser | — | Not supported — Yahoo Finance blocks CORS. Use a server-side proxy. |
308
+
309
+ ---
310
+
311
+ ## Contributing
312
+
313
+ See [CONTRIBUTING.md](CONTRIBUTING.md). All contributions welcome.
314
+
315
+ ```bash
316
+ git clone https://github.com/piyushgupta344/market-feed
317
+ cd market-feed
318
+ pnpm install
319
+ pnpm test
320
+ ```
321
+
322
+ ---
323
+
324
+ ## Disclaimer
325
+
326
+ This library is not affiliated with or endorsed by Yahoo Finance, Alpha Vantage, or Polygon.io. Data is provided for informational purposes only and should not be used as the sole basis for investment decisions.
327
+
328
+ ---
329
+
330
+ ## License
331
+
332
+ [MIT](LICENSE)