tradingview-mcp-server 0.0.1
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/LICENSE +21 -0
- package/README.md +267 -0
- package/dist/api/client.d.ts +11 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +45 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/types.d.ts +68 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +5 -0
- package/dist/api/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +265 -0
- package/dist/index.js.map +1 -0
- package/dist/resources/presets.d.ts +24 -0
- package/dist/resources/presets.d.ts.map +1 -0
- package/dist/resources/presets.js +85 -0
- package/dist/resources/presets.js.map +1 -0
- package/dist/tests/cache.test.d.ts +2 -0
- package/dist/tests/cache.test.d.ts.map +1 -0
- package/dist/tests/cache.test.js +41 -0
- package/dist/tests/cache.test.js.map +1 -0
- package/dist/tests/fields.test.d.ts +2 -0
- package/dist/tests/fields.test.d.ts.map +1 -0
- package/dist/tests/fields.test.js +56 -0
- package/dist/tests/fields.test.js.map +1 -0
- package/dist/tests/presets.test.d.ts +2 -0
- package/dist/tests/presets.test.d.ts.map +1 -0
- package/dist/tests/presets.test.js +59 -0
- package/dist/tests/presets.test.js.map +1 -0
- package/dist/tests/rateLimit.test.d.ts +2 -0
- package/dist/tests/rateLimit.test.d.ts.map +1 -0
- package/dist/tests/rateLimit.test.js +44 -0
- package/dist/tests/rateLimit.test.js.map +1 -0
- package/dist/tools/fields.d.ts +8 -0
- package/dist/tools/fields.d.ts.map +1 -0
- package/dist/tools/fields.js +229 -0
- package/dist/tools/fields.js.map +1 -0
- package/dist/tools/screen.d.ts +17 -0
- package/dist/tools/screen.d.ts.map +1 -0
- package/dist/tools/screen.js +171 -0
- package/dist/tools/screen.js.map +1 -0
- package/dist/utils/cache.d.ts +13 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +45 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/rateLimit.d.ts +11 -0
- package/dist/utils/rateLimit.d.ts.map +1 -0
- package/dist/utils/rateLimit.js +28 -0
- package/dist/utils/rateLimit.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import { RateLimiter } from "../utils/rateLimit.js";
|
|
4
|
+
describe("RateLimiter", () => {
|
|
5
|
+
it("should allow requests within limit", async () => {
|
|
6
|
+
const limiter = new RateLimiter(5); // 5 requests per minute
|
|
7
|
+
const start = Date.now();
|
|
8
|
+
// Should allow 5 requests immediately
|
|
9
|
+
for (let i = 0; i < 5; i++) {
|
|
10
|
+
await limiter.acquire();
|
|
11
|
+
}
|
|
12
|
+
const elapsed = Date.now() - start;
|
|
13
|
+
// Should complete quickly (within 100ms)
|
|
14
|
+
assert.ok(elapsed < 100, `Took too long: ${elapsed}ms`);
|
|
15
|
+
});
|
|
16
|
+
it("should throttle requests exceeding limit", async () => {
|
|
17
|
+
const limiter = new RateLimiter(2); // 2 requests per minute
|
|
18
|
+
const start = Date.now();
|
|
19
|
+
// First 2 requests should be fast
|
|
20
|
+
await limiter.acquire();
|
|
21
|
+
await limiter.acquire();
|
|
22
|
+
const afterTwo = Date.now() - start;
|
|
23
|
+
assert.ok(afterTwo < 100, "First two requests should be fast");
|
|
24
|
+
// Third request should be delayed
|
|
25
|
+
await limiter.acquire();
|
|
26
|
+
const afterThree = Date.now() - start;
|
|
27
|
+
// Should wait close to 60 seconds (allow some margin)
|
|
28
|
+
assert.ok(afterThree >= 59000, `Should wait ~60s, but only waited ${afterThree}ms`);
|
|
29
|
+
});
|
|
30
|
+
it("should handle multiple requests correctly", async () => {
|
|
31
|
+
const limiter = new RateLimiter(3);
|
|
32
|
+
// Fire 3 requests - should complete quickly
|
|
33
|
+
const promises = [
|
|
34
|
+
limiter.acquire(),
|
|
35
|
+
limiter.acquire(),
|
|
36
|
+
limiter.acquire(),
|
|
37
|
+
];
|
|
38
|
+
const start = Date.now();
|
|
39
|
+
await Promise.all(promises);
|
|
40
|
+
const elapsed = Date.now() - start;
|
|
41
|
+
assert.ok(elapsed < 100, `Should complete quickly, took ${elapsed}ms`);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=rateLimit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rateLimit.test.js","sourceRoot":"","sources":["../../src/tests/rateLimit.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;QAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEzB,sCAAsC;QACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QAC1B,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QACnC,yCAAyC;QACzC,MAAM,CAAC,EAAE,CAAC,OAAO,GAAG,GAAG,EAAE,kBAAkB,OAAO,IAAI,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;QAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEzB,kCAAkC;QAClC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QAExB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QACpC,MAAM,CAAC,EAAE,CAAC,QAAQ,GAAG,GAAG,EAAE,mCAAmC,CAAC,CAAC;QAE/D,kCAAkC;QAClC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QAExB,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QACtC,sDAAsD;QACtD,MAAM,CAAC,EAAE,CAAC,UAAU,IAAI,KAAK,EAAE,qCAAqC,UAAU,IAAI,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC;QAEnC,4CAA4C;QAC5C,MAAM,QAAQ,GAAG;YACf,OAAO,CAAC,OAAO,EAAE;YACjB,OAAO,CAAC,OAAO,EAAE;YACjB,OAAO,CAAC,OAAO,EAAE;SAClB,CAAC;QAEF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QAEnC,MAAM,CAAC,EAAE,CAAC,OAAO,GAAG,GAAG,EAAE,iCAAiC,OAAO,IAAI,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../../src/tools/fields.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAiB,eAAe,EAAE,MAAM,iBAAiB,CAAC;AA+MtE,qBAAa,UAAU;IACrB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,GAAG;CAyBxC"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Field listing and metadata
|
|
3
|
+
*/
|
|
4
|
+
// Common stock fields
|
|
5
|
+
const STOCK_FIELDS = [
|
|
6
|
+
// Fundamental
|
|
7
|
+
{
|
|
8
|
+
name: "market_cap_basic",
|
|
9
|
+
label: "Market Capitalization",
|
|
10
|
+
category: "fundamental",
|
|
11
|
+
type: "currency",
|
|
12
|
+
description: "Total market value of company",
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: "return_on_equity",
|
|
16
|
+
label: "Return on Equity (TTM)",
|
|
17
|
+
category: "fundamental",
|
|
18
|
+
type: "percent",
|
|
19
|
+
description: "Profitability relative to shareholder equity",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: "price_earnings_ttm",
|
|
23
|
+
label: "P/E Ratio (TTM)",
|
|
24
|
+
category: "fundamental",
|
|
25
|
+
type: "number",
|
|
26
|
+
description: "Price to earnings ratio",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "price_book_fq",
|
|
30
|
+
label: "P/B Ratio",
|
|
31
|
+
category: "fundamental",
|
|
32
|
+
type: "number",
|
|
33
|
+
description: "Price to book value ratio",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "price_sales_ratio",
|
|
37
|
+
label: "P/S Ratio",
|
|
38
|
+
category: "fundamental",
|
|
39
|
+
type: "number",
|
|
40
|
+
description: "Price to sales ratio",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "debt_to_equity",
|
|
44
|
+
label: "Debt/Equity Ratio",
|
|
45
|
+
category: "fundamental",
|
|
46
|
+
type: "number",
|
|
47
|
+
description: "Total debt relative to shareholder equity",
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: "net_margin_ttm",
|
|
51
|
+
label: "Net Margin (TTM)",
|
|
52
|
+
category: "fundamental",
|
|
53
|
+
type: "percent",
|
|
54
|
+
description: "Net income as percentage of revenue",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "after_tax_margin",
|
|
58
|
+
label: "After-Tax Margin",
|
|
59
|
+
category: "fundamental",
|
|
60
|
+
type: "percent",
|
|
61
|
+
description: "Profit margin after taxes",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: "operating_margin",
|
|
65
|
+
label: "Operating Margin",
|
|
66
|
+
category: "fundamental",
|
|
67
|
+
type: "percent",
|
|
68
|
+
description: "Operating income as percentage of revenue",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: "dividend_yield_recent",
|
|
72
|
+
label: "Dividend Yield",
|
|
73
|
+
category: "fundamental",
|
|
74
|
+
type: "percent",
|
|
75
|
+
description: "Annual dividend as percentage of price",
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: "earnings_per_share_diluted_ttm",
|
|
79
|
+
label: "EPS (Diluted, TTM)",
|
|
80
|
+
category: "fundamental",
|
|
81
|
+
type: "currency",
|
|
82
|
+
description: "Earnings per share",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: "total_revenue",
|
|
86
|
+
label: "Total Revenue",
|
|
87
|
+
category: "fundamental",
|
|
88
|
+
type: "currency",
|
|
89
|
+
description: "Total company revenue",
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: "net_income",
|
|
93
|
+
label: "Net Income",
|
|
94
|
+
category: "fundamental",
|
|
95
|
+
type: "currency",
|
|
96
|
+
description: "Total net profit",
|
|
97
|
+
},
|
|
98
|
+
// Technical
|
|
99
|
+
{
|
|
100
|
+
name: "RSI",
|
|
101
|
+
label: "RSI (14)",
|
|
102
|
+
category: "technical",
|
|
103
|
+
type: "number",
|
|
104
|
+
description: "Relative Strength Index momentum oscillator",
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: "SMA50",
|
|
108
|
+
label: "SMA 50",
|
|
109
|
+
category: "technical",
|
|
110
|
+
type: "number",
|
|
111
|
+
description: "50-day Simple Moving Average",
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: "SMA200",
|
|
115
|
+
label: "SMA 200",
|
|
116
|
+
category: "technical",
|
|
117
|
+
type: "number",
|
|
118
|
+
description: "200-day Simple Moving Average",
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: "EMA10",
|
|
122
|
+
label: "EMA 10",
|
|
123
|
+
category: "technical",
|
|
124
|
+
type: "number",
|
|
125
|
+
description: "10-day Exponential Moving Average",
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: "Volatility.M",
|
|
129
|
+
label: "Volatility (Monthly)",
|
|
130
|
+
category: "technical",
|
|
131
|
+
type: "percent",
|
|
132
|
+
description: "1-month price volatility",
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
name: "ATR",
|
|
136
|
+
label: "Average True Range",
|
|
137
|
+
category: "technical",
|
|
138
|
+
type: "number",
|
|
139
|
+
description: "Measure of volatility",
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: "ADX",
|
|
143
|
+
label: "ADX",
|
|
144
|
+
category: "technical",
|
|
145
|
+
type: "number",
|
|
146
|
+
description: "Average Directional Index",
|
|
147
|
+
},
|
|
148
|
+
// Performance
|
|
149
|
+
{
|
|
150
|
+
name: "close",
|
|
151
|
+
label: "Current Price",
|
|
152
|
+
category: "performance",
|
|
153
|
+
type: "currency",
|
|
154
|
+
description: "Current stock price",
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: "change",
|
|
158
|
+
label: "Change %",
|
|
159
|
+
category: "performance",
|
|
160
|
+
type: "percent",
|
|
161
|
+
description: "Daily price change percentage",
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: "volume",
|
|
165
|
+
label: "Volume",
|
|
166
|
+
category: "performance",
|
|
167
|
+
type: "number",
|
|
168
|
+
description: "Trading volume",
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: "Perf.W",
|
|
172
|
+
label: "Weekly Performance",
|
|
173
|
+
category: "performance",
|
|
174
|
+
type: "percent",
|
|
175
|
+
description: "1-week price change",
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: "Perf.1M",
|
|
179
|
+
label: "Monthly Performance",
|
|
180
|
+
category: "performance",
|
|
181
|
+
type: "percent",
|
|
182
|
+
description: "1-month price change",
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: "Perf.3M",
|
|
186
|
+
label: "3-Month Performance",
|
|
187
|
+
category: "performance",
|
|
188
|
+
type: "percent",
|
|
189
|
+
description: "3-month price change",
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: "Perf.Y",
|
|
193
|
+
label: "Yearly Performance",
|
|
194
|
+
category: "performance",
|
|
195
|
+
type: "percent",
|
|
196
|
+
description: "1-year price change",
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: "Perf.YTD",
|
|
200
|
+
label: "YTD Performance",
|
|
201
|
+
category: "performance",
|
|
202
|
+
type: "percent",
|
|
203
|
+
description: "Year-to-date price change",
|
|
204
|
+
},
|
|
205
|
+
];
|
|
206
|
+
export class FieldsTool {
|
|
207
|
+
listFields(input) {
|
|
208
|
+
const { asset_type = "stock", category } = input;
|
|
209
|
+
// For MVP, only stock fields are implemented
|
|
210
|
+
if (asset_type !== "stock") {
|
|
211
|
+
return {
|
|
212
|
+
message: `Fields for ${asset_type} will be available in future versions`,
|
|
213
|
+
fields: [],
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
let fields = STOCK_FIELDS;
|
|
217
|
+
// Filter by category if specified
|
|
218
|
+
if (category) {
|
|
219
|
+
fields = fields.filter((f) => f.category === category);
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
asset_type,
|
|
223
|
+
category: category || "all",
|
|
224
|
+
field_count: fields.length,
|
|
225
|
+
fields,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fields.js","sourceRoot":"","sources":["../../src/tools/fields.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stock screening tool
|
|
3
|
+
*/
|
|
4
|
+
import type { ScreenStocksInput } from "../api/types.js";
|
|
5
|
+
import type { TradingViewClient } from "../api/client.js";
|
|
6
|
+
import type { Cache } from "../utils/cache.js";
|
|
7
|
+
import type { RateLimiter } from "../utils/rateLimit.js";
|
|
8
|
+
export declare class ScreenTool {
|
|
9
|
+
private client;
|
|
10
|
+
private cache;
|
|
11
|
+
private rateLimiter;
|
|
12
|
+
constructor(client: TradingViewClient, cache: Cache, rateLimiter: RateLimiter);
|
|
13
|
+
screenStocks(input: ScreenStocksInput): Promise<any>;
|
|
14
|
+
screenForex(input: Omit<ScreenStocksInput, "markets">): Promise<any>;
|
|
15
|
+
screenCrypto(input: Omit<ScreenStocksInput, "markets">): Promise<any>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=screen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../../src/tools/screen.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,iBAAiB,EAIlB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AA4BzD,qBAAa,UAAU;IAEnB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,WAAW;gBAFX,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,WAAW;IAG5B,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC;IAoFpD,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,iBAAiB,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IA+CpE,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,iBAAiB,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;CA8C5E"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stock screening tool
|
|
3
|
+
*/
|
|
4
|
+
// Operator mapping from MCP to TradingView API
|
|
5
|
+
const OPERATOR_MAP = {
|
|
6
|
+
greater: "greater",
|
|
7
|
+
less: "less",
|
|
8
|
+
greater_or_equal: "egreater",
|
|
9
|
+
less_or_equal: "eless",
|
|
10
|
+
equal: "equal",
|
|
11
|
+
not_equal: "nequal",
|
|
12
|
+
in_range: "in_range",
|
|
13
|
+
not_in_range: "not_in_range",
|
|
14
|
+
crosses: "crosses",
|
|
15
|
+
crosses_above: "crosses_above",
|
|
16
|
+
crosses_below: "crosses_below",
|
|
17
|
+
match: "match",
|
|
18
|
+
};
|
|
19
|
+
// Common fields to include in response
|
|
20
|
+
const DEFAULT_COLUMNS = [
|
|
21
|
+
"name",
|
|
22
|
+
"close",
|
|
23
|
+
"market_cap_basic",
|
|
24
|
+
"return_on_equity",
|
|
25
|
+
"price_earnings_ttm",
|
|
26
|
+
"debt_to_equity",
|
|
27
|
+
];
|
|
28
|
+
export class ScreenTool {
|
|
29
|
+
client;
|
|
30
|
+
cache;
|
|
31
|
+
rateLimiter;
|
|
32
|
+
constructor(client, cache, rateLimiter) {
|
|
33
|
+
this.client = client;
|
|
34
|
+
this.cache = cache;
|
|
35
|
+
this.rateLimiter = rateLimiter;
|
|
36
|
+
}
|
|
37
|
+
async screenStocks(input) {
|
|
38
|
+
const { filters, markets = ["america"], sort_by = "market_cap_basic", sort_order = "desc", limit = 20, } = input;
|
|
39
|
+
// Validate limit
|
|
40
|
+
if (limit < 1 || limit > 200) {
|
|
41
|
+
throw new Error("Limit must be between 1 and 200");
|
|
42
|
+
}
|
|
43
|
+
// Build cache key
|
|
44
|
+
const cacheKey = JSON.stringify({ filters, markets, sort_by, sort_order, limit });
|
|
45
|
+
// Check cache
|
|
46
|
+
const cached = this.cache.get(cacheKey);
|
|
47
|
+
if (cached) {
|
|
48
|
+
return cached;
|
|
49
|
+
}
|
|
50
|
+
// Convert filters to TradingView format
|
|
51
|
+
const tvFilters = filters.map((f) => {
|
|
52
|
+
const operation = OPERATOR_MAP[f.operator];
|
|
53
|
+
if (!operation) {
|
|
54
|
+
throw new Error(`Unknown operator: ${f.operator}`);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
left: f.field,
|
|
58
|
+
operation,
|
|
59
|
+
right: f.value,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
// Extract unique fields from filters for columns
|
|
63
|
+
const filterFields = filters.map((f) => f.field);
|
|
64
|
+
const columns = [...new Set([...DEFAULT_COLUMNS, ...filterFields])];
|
|
65
|
+
// Build request
|
|
66
|
+
const request = {
|
|
67
|
+
filter: tvFilters,
|
|
68
|
+
columns,
|
|
69
|
+
sort: {
|
|
70
|
+
sortBy: sort_by,
|
|
71
|
+
sortOrder: sort_order,
|
|
72
|
+
},
|
|
73
|
+
range: [0, limit],
|
|
74
|
+
options: { lang: "en" },
|
|
75
|
+
symbols: {
|
|
76
|
+
query: { types: [] },
|
|
77
|
+
tickers: [],
|
|
78
|
+
},
|
|
79
|
+
markets,
|
|
80
|
+
};
|
|
81
|
+
// Rate limit
|
|
82
|
+
await this.rateLimiter.acquire();
|
|
83
|
+
// Make request
|
|
84
|
+
const response = await this.client.scanStocks(request);
|
|
85
|
+
// Format response
|
|
86
|
+
const result = {
|
|
87
|
+
total_count: response.totalCount,
|
|
88
|
+
stocks: response.data.map((item) => {
|
|
89
|
+
const stock = { symbol: item.s };
|
|
90
|
+
columns.forEach((col, idx) => {
|
|
91
|
+
stock[col] = item.d[idx];
|
|
92
|
+
});
|
|
93
|
+
return stock;
|
|
94
|
+
}),
|
|
95
|
+
};
|
|
96
|
+
// Cache result
|
|
97
|
+
this.cache.set(cacheKey, result);
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
async screenForex(input) {
|
|
101
|
+
// Similar to screenStocks but without markets
|
|
102
|
+
const { filters, sort_by = "volume", sort_order = "desc", limit = 20, } = input;
|
|
103
|
+
const cacheKey = JSON.stringify({ type: "forex", filters, sort_by, sort_order, limit });
|
|
104
|
+
const cached = this.cache.get(cacheKey);
|
|
105
|
+
if (cached)
|
|
106
|
+
return cached;
|
|
107
|
+
const tvFilters = filters.map((f) => ({
|
|
108
|
+
left: f.field,
|
|
109
|
+
operation: OPERATOR_MAP[f.operator] || "greater",
|
|
110
|
+
right: f.value,
|
|
111
|
+
}));
|
|
112
|
+
const filterFields = filters.map((f) => f.field);
|
|
113
|
+
const columns = [...new Set(["name", "close", "change", ...filterFields])];
|
|
114
|
+
const request = {
|
|
115
|
+
filter: tvFilters,
|
|
116
|
+
columns,
|
|
117
|
+
sort: { sortBy: sort_by, sortOrder: sort_order },
|
|
118
|
+
range: [0, limit],
|
|
119
|
+
options: { lang: "en" },
|
|
120
|
+
symbols: { query: { types: [] }, tickers: [] },
|
|
121
|
+
};
|
|
122
|
+
await this.rateLimiter.acquire();
|
|
123
|
+
const response = await this.client.scanForex(request);
|
|
124
|
+
const result = {
|
|
125
|
+
total_count: response.totalCount,
|
|
126
|
+
pairs: response.data.map((item) => {
|
|
127
|
+
const pair = { symbol: item.s };
|
|
128
|
+
columns.forEach((col, idx) => { pair[col] = item.d[idx]; });
|
|
129
|
+
return pair;
|
|
130
|
+
}),
|
|
131
|
+
};
|
|
132
|
+
this.cache.set(cacheKey, result);
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
async screenCrypto(input) {
|
|
136
|
+
// Similar to forex
|
|
137
|
+
const { filters, sort_by = "market_cap_basic", sort_order = "desc", limit = 20, } = input;
|
|
138
|
+
const cacheKey = JSON.stringify({ type: "crypto", filters, sort_by, sort_order, limit });
|
|
139
|
+
const cached = this.cache.get(cacheKey);
|
|
140
|
+
if (cached)
|
|
141
|
+
return cached;
|
|
142
|
+
const tvFilters = filters.map((f) => ({
|
|
143
|
+
left: f.field,
|
|
144
|
+
operation: OPERATOR_MAP[f.operator] || "greater",
|
|
145
|
+
right: f.value,
|
|
146
|
+
}));
|
|
147
|
+
const filterFields = filters.map((f) => f.field);
|
|
148
|
+
const columns = [...new Set(["name", "close", "market_cap_basic", "change", ...filterFields])];
|
|
149
|
+
const request = {
|
|
150
|
+
filter: tvFilters,
|
|
151
|
+
columns,
|
|
152
|
+
sort: { sortBy: sort_by, sortOrder: sort_order },
|
|
153
|
+
range: [0, limit],
|
|
154
|
+
options: { lang: "en" },
|
|
155
|
+
symbols: { query: { types: [] }, tickers: [] },
|
|
156
|
+
};
|
|
157
|
+
await this.rateLimiter.acquire();
|
|
158
|
+
const response = await this.client.scanCrypto(request);
|
|
159
|
+
const result = {
|
|
160
|
+
total_count: response.totalCount,
|
|
161
|
+
cryptocurrencies: response.data.map((item) => {
|
|
162
|
+
const crypto = { symbol: item.s };
|
|
163
|
+
columns.forEach((col, idx) => { crypto[col] = item.d[idx]; });
|
|
164
|
+
return crypto;
|
|
165
|
+
}),
|
|
166
|
+
};
|
|
167
|
+
this.cache.set(cacheKey, result);
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=screen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen.js","sourceRoot":"","sources":["../../src/tools/screen.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple in-memory cache with TTL
|
|
3
|
+
*/
|
|
4
|
+
export declare class Cache {
|
|
5
|
+
private store;
|
|
6
|
+
private ttl;
|
|
7
|
+
constructor(ttlSeconds?: number);
|
|
8
|
+
get(key: string): any | null;
|
|
9
|
+
set(key: string, data: any): void;
|
|
10
|
+
clear(): void;
|
|
11
|
+
startCleanup(intervalMs?: number): NodeJS.Timeout;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,qBAAa,KAAK;IAChB,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,GAAG,CAAS;gBAER,UAAU,GAAE,MAAY;IAIpC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAc5B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IASjC,KAAK,IAAI,IAAI;IAKb,YAAY,CAAC,UAAU,GAAE,MAAc,GAAG,MAAM,CAAC,OAAO;CAUzD"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple in-memory cache with TTL
|
|
3
|
+
*/
|
|
4
|
+
export class Cache {
|
|
5
|
+
store = new Map();
|
|
6
|
+
ttl;
|
|
7
|
+
constructor(ttlSeconds = 300) {
|
|
8
|
+
this.ttl = ttlSeconds * 1000;
|
|
9
|
+
}
|
|
10
|
+
get(key) {
|
|
11
|
+
if (this.ttl === 0)
|
|
12
|
+
return null; // Caching disabled
|
|
13
|
+
const entry = this.store.get(key);
|
|
14
|
+
if (!entry)
|
|
15
|
+
return null;
|
|
16
|
+
if (Date.now() >= entry.expires) {
|
|
17
|
+
this.store.delete(key);
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
return entry.data;
|
|
21
|
+
}
|
|
22
|
+
set(key, data) {
|
|
23
|
+
if (this.ttl === 0)
|
|
24
|
+
return; // Caching disabled
|
|
25
|
+
this.store.set(key, {
|
|
26
|
+
data,
|
|
27
|
+
expires: Date.now() + this.ttl,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
clear() {
|
|
31
|
+
this.store.clear();
|
|
32
|
+
}
|
|
33
|
+
// Periodic cleanup of expired entries
|
|
34
|
+
startCleanup(intervalMs = 60000) {
|
|
35
|
+
return setInterval(() => {
|
|
36
|
+
const now = Date.now();
|
|
37
|
+
for (const [key, entry] of this.store.entries()) {
|
|
38
|
+
if (now >= entry.expires) {
|
|
39
|
+
this.store.delete(key);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}, intervalMs);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,MAAM,OAAO,KAAK;IACR,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;IACtC,GAAG,CAAS;IAEpB,YAAY,aAAqB,GAAG;QAClC,IAAI,CAAC,GAAG,GAAG,UAAU,GAAG,IAAI,CAAC;IAC/B,CAAC;IAED,GAAG,CAAC,GAAW;QACb,IAAI,IAAI,CAAC,GAAG,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC,CAAC,mBAAmB;QAEpD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YAChC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC;IACpB,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,IAAS;QACxB,IAAI,IAAI,CAAC,GAAG,KAAK,CAAC;YAAE,OAAO,CAAC,mBAAmB;QAE/C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAClB,IAAI;YACJ,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG;SAC/B,CAAC,CAAC;IACL,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,sCAAsC;IACtC,YAAY,CAAC,aAAqB,KAAK;QACrC,OAAO,WAAW,CAAC,GAAG,EAAE;YACtB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;gBAChD,IAAI,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;oBACzB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACzB,CAAC;YACH,CAAC;QACH,CAAC,EAAE,UAAU,CAAC,CAAC;IACjB,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rateLimit.d.ts","sourceRoot":"","sources":["../../src/utils/rateLimit.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;gBAEb,iBAAiB,GAAE,MAAW;IAKpC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAmB/B"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple rate limiter
|
|
3
|
+
*/
|
|
4
|
+
export class RateLimiter {
|
|
5
|
+
requests = [];
|
|
6
|
+
maxRequests;
|
|
7
|
+
windowMs;
|
|
8
|
+
constructor(requestsPerMinute = 10) {
|
|
9
|
+
this.maxRequests = requestsPerMinute;
|
|
10
|
+
this.windowMs = 60000; // 1 minute
|
|
11
|
+
}
|
|
12
|
+
async acquire() {
|
|
13
|
+
const now = Date.now();
|
|
14
|
+
// Clean up old requests outside the window
|
|
15
|
+
this.requests = this.requests.filter((time) => now - time < this.windowMs);
|
|
16
|
+
if (this.requests.length >= this.maxRequests) {
|
|
17
|
+
// Calculate how long to wait
|
|
18
|
+
const oldestRequest = this.requests[0];
|
|
19
|
+
const waitTime = this.windowMs - (now - oldestRequest);
|
|
20
|
+
if (waitTime > 0) {
|
|
21
|
+
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
22
|
+
return this.acquire(); // Retry after waiting
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
this.requests.push(now);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=rateLimit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rateLimit.js","sourceRoot":"","sources":["../../src/utils/rateLimit.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,OAAO,WAAW;IACd,QAAQ,GAAa,EAAE,CAAC;IACxB,WAAW,CAAS;IACpB,QAAQ,CAAS;IAEzB,YAAY,oBAA4B,EAAE;QACxC,IAAI,CAAC,WAAW,GAAG,iBAAiB,CAAC;QACrC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,CAAC,WAAW;IACpC,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,2CAA2C;QAC3C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QAE3E,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YAC7C,6BAA6B;YAC7B,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,GAAG,GAAG,aAAa,CAAC,CAAC;YAEvD,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;gBACjB,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;gBAC9D,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,sBAAsB;YAC/C,CAAC;QACH,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;CACF"}
|