@kuandotdev/indicator 0.1.1 → 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.
Files changed (80) hide show
  1. package/README.md +2 -7
  2. package/package.json +4 -1
  3. package/project/.cursor/rules/agent-docs.mdc +16 -0
  4. package/project/.cursor/rules/api-credential-storage.mdc +16 -0
  5. package/project/.cursor/rules/pinescript-v6.mdc +16 -0
  6. package/project/.cursor/rules/stock-model-forecast.mdc +16 -0
  7. package/project/.cursor/rules/system-prompt-injection.mdc +16 -0
  8. package/project/.cursor/rules/system-prompt-updater.mdc +16 -0
  9. package/project/.cursor/rules/tradingview-stock-data.mdc +16 -0
  10. package/project/.env.example +44 -0
  11. package/project/.npm-packaged-project +1 -0
  12. package/project/.pi/APPEND_SYSTEM.md +338 -0
  13. package/project/.pi/settings.json +8 -0
  14. package/project/AGENTS.md +538 -0
  15. package/project/CLAUDE.md +538 -0
  16. package/project/GEMINI.md +538 -0
  17. package/project/Makefile +488 -0
  18. package/project/README.md +419 -0
  19. package/project/conda-env-active.sh +98 -0
  20. package/project/conda-env-deactive.sh +42 -0
  21. package/project/docs/agent-install.md +446 -0
  22. package/project/docs/agent-skill-directory.md +222 -0
  23. package/project/docs/integration.html +271 -0
  24. package/project/packages/indicator/README.md +39 -0
  25. package/project/packages/indicator/package.json +40 -0
  26. package/project/packages/indicator/scripts/build-project-snapshot.js +57 -0
  27. package/project/packages/indicator/src/cli.js +368 -0
  28. package/project/packages/tradingview-stock-data-skill/README.md +112 -0
  29. package/project/packages/tradingview-stock-data-skill/extensions/stock-prompt-injector.ts +121 -0
  30. package/project/packages/tradingview-stock-data-skill/package.json +35 -0
  31. package/project/packages/tradingview-stock-data-skill/scripts/postinstall.sh +73 -0
  32. package/project/packages/tradingview-stock-data-skill/skills/tradingview-stock-data/SKILL.md +241 -0
  33. package/project/pyproject.toml +68 -0
  34. package/project/screenshots/.gitkeep +0 -0
  35. package/project/scripts/indicators/example_rsi_bands.pine +27 -0
  36. package/project/scripts/indicators/tsla_levels.pine +57 -0
  37. package/project/skills/agent-docs/SKILL.md +56 -0
  38. package/project/skills/api-credential-storage/SKILL.md +83 -0
  39. package/project/skills/api-credential-storage/scripts/upsert_env.py +151 -0
  40. package/project/skills/pinescript-v6/SKILL.md +129 -0
  41. package/project/skills/pinescript-v6/reference/built-ins.md +219 -0
  42. package/project/skills/pinescript-v6/reference/templates/alert-webhook.pine +76 -0
  43. package/project/skills/pinescript-v6/reference/templates/indicator.pine +48 -0
  44. package/project/skills/pinescript-v6/reference/templates/strategy.pine +50 -0
  45. package/project/skills/pinescript-v6/reference/v5-to-v6-migration.md +102 -0
  46. package/project/skills/pinescript-v6/reference/v6-language.md +202 -0
  47. package/project/skills/stock-model-forecast/SKILL.md +192 -0
  48. package/project/skills/system-prompt-injection/CUSTOM_SYSTEM_PROMPT.md +333 -0
  49. package/project/skills/system-prompt-injection/DEFAULT_SYSTEM_PROMPT.md +327 -0
  50. package/project/skills/system-prompt-injection/SKILL.md +90 -0
  51. package/project/skills/system-prompt-injection/SYSTEM_PROMPT.md +23 -0
  52. package/project/skills/system-prompt-updater/SKILL.md +82 -0
  53. package/project/skills/system-prompt-updater/scripts/system_prompt_update.sh +106 -0
  54. package/project/skills/tradingview-stock-data/SKILL.md +272 -0
  55. package/project/src/tv_indicator/__init__.py +0 -0
  56. package/project/src/tv_indicator/browser/__init__.py +0 -0
  57. package/project/src/tv_indicator/browser/automation.py +541 -0
  58. package/project/src/tv_indicator/browser/selectors.py +70 -0
  59. package/project/src/tv_indicator/cli/__init__.py +0 -0
  60. package/project/src/tv_indicator/cli/browser_cmds.py +92 -0
  61. package/project/src/tv_indicator/cli/data_cmds.py +178 -0
  62. package/project/src/tv_indicator/cli/main.py +56 -0
  63. package/project/src/tv_indicator/cli/model_cmds.py +255 -0
  64. package/project/src/tv_indicator/cli/pine_cmds.py +140 -0
  65. package/project/src/tv_indicator/config.py +98 -0
  66. package/project/src/tv_indicator/data/__init__.py +0 -0
  67. package/project/src/tv_indicator/data/client.py +187 -0
  68. package/project/src/tv_indicator/data/screener.py +268 -0
  69. package/project/src/tv_indicator/mcp/__init__.py +0 -0
  70. package/project/src/tv_indicator/mcp/agent_server.py +398 -0
  71. package/project/src/tv_indicator/mcp/browser_server.py +133 -0
  72. package/project/src/tv_indicator/mcp/data_server.py +239 -0
  73. package/project/src/tv_indicator/model/__init__.py +19 -0
  74. package/project/src/tv_indicator/model/forecast.py +693 -0
  75. package/project/tools/import_agent_tools.sh +503 -0
  76. package/project/tools/install_skills.sh +673 -0
  77. package/project/tools/interactive_install.sh +917 -0
  78. package/project/tools/progress.sh +114 -0
  79. package/project/tools/uninstall_agent_tools.sh +373 -0
  80. package/src/cli.js +22 -25
@@ -0,0 +1,239 @@
1
+ """MCP server: TradingView data and server-side model forecasts.
2
+
3
+ Exposes the same functions as `training-view data ...` and
4
+ `training-view model forecast ...` so any MCP-aware agent can call them.
5
+
6
+ Register in claude_desktop_config.json:
7
+ {
8
+ "mcpServers": {
9
+ "training-view-data": {
10
+ "command": "training-view-mcp-data",
11
+ "env": { "TV_SESSIONID": "..." }
12
+ }
13
+ }
14
+ }
15
+ """
16
+ from __future__ import annotations
17
+
18
+ import asyncio
19
+ import json
20
+ from typing import Any
21
+
22
+ from mcp.server import Server
23
+ from mcp.server.stdio import stdio_server
24
+ from mcp.types import TextContent, Tool
25
+
26
+ server = Server("training-view-data")
27
+
28
+
29
+ # ─── Tool definitions ──────────────────────────────────────────────────────
30
+
31
+
32
+ @server.list_tools()
33
+ async def list_tools() -> list[Tool]:
34
+ return [
35
+ Tool(
36
+ name="get_ohlcv",
37
+ description=(
38
+ "Fetch OHLCV candles for a TradingView symbol. "
39
+ "Returns JSON with `index` (timestamps) and column arrays."
40
+ ),
41
+ inputSchema={
42
+ "type": "object",
43
+ "properties": {
44
+ "symbol": {"type": "string", "description": "e.g. 'NASDAQ:AAPL' or 'AAPL'"},
45
+ "interval": {
46
+ "type": "string",
47
+ "enum": ["1", "3", "5", "15", "30", "45", "60", "120", "180", "240", "1D", "1W", "1M"],
48
+ "default": "1D",
49
+ },
50
+ "n_bars": {"type": "integer", "default": 500, "minimum": 1, "maximum": 5000},
51
+ "exchange": {"type": "string", "description": "Optional if not in symbol"},
52
+ "extended_session": {"type": "boolean", "default": False},
53
+ },
54
+ "required": ["symbol"],
55
+ },
56
+ ),
57
+ Tool(
58
+ name="search_symbol",
59
+ description="Search TradingView symbols by ticker or company name.",
60
+ inputSchema={
61
+ "type": "object",
62
+ "properties": {
63
+ "query": {"type": "string"},
64
+ "limit": {"type": "integer", "default": 20, "minimum": 1, "maximum": 100},
65
+ },
66
+ "required": ["query"],
67
+ },
68
+ ),
69
+ Tool(
70
+ name="screener",
71
+ description=(
72
+ "Run a TradingView screener query. Filters are tuples of (column, op, value). "
73
+ "Ops: >, <, >=, <=, =, !="
74
+ ),
75
+ inputSchema={
76
+ "type": "object",
77
+ "properties": {
78
+ "market": {"type": "string", "default": "america"},
79
+ "columns": {"type": "array", "items": {"type": "string"}},
80
+ "filters": {
81
+ "type": "array",
82
+ "items": {
83
+ "type": "array",
84
+ "prefixItems": [
85
+ {"type": "string"},
86
+ {"type": "string"},
87
+ {},
88
+ ],
89
+ "minItems": 3,
90
+ "maxItems": 3,
91
+ },
92
+ },
93
+ "order_by": {
94
+ "type": "array",
95
+ "prefixItems": [{"type": "string"}, {"type": "boolean"}],
96
+ "minItems": 2,
97
+ "maxItems": 2,
98
+ },
99
+ "limit": {"type": "integer", "default": 50},
100
+ },
101
+ },
102
+ ),
103
+ Tool(
104
+ name="technical_rating",
105
+ description="Get TradingView's Strong Buy/Buy/Neutral/Sell/Strong Sell rating for a symbol.",
106
+ inputSchema={
107
+ "type": "object",
108
+ "properties": {
109
+ "symbol": {"type": "string"},
110
+ "interval": {"type": "string", "default": "1D"},
111
+ },
112
+ "required": ["symbol"],
113
+ },
114
+ ),
115
+ Tool(
116
+ name="model_forecast",
117
+ description="Fetch the server-side xs_range 20-trading-day forecast for a stock/ETF/index symbol.",
118
+ inputSchema={
119
+ "type": "object",
120
+ "properties": {
121
+ "symbol": {"type": "string", "description": "e.g. 'NASDAQ:TSLA' or 'TSLA'"},
122
+ "refresh": {"type": "boolean", "default": False},
123
+ "period": {"type": "string", "default": "10y"},
124
+ },
125
+ "required": ["symbol"],
126
+ },
127
+ ),
128
+ ]
129
+
130
+
131
+ # ─── Tool dispatch ─────────────────────────────────────────────────────────
132
+
133
+
134
+ @server.call_tool()
135
+ async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
136
+ if name == "get_ohlcv":
137
+ return await _get_ohlcv(arguments)
138
+ if name == "search_symbol":
139
+ return await _search_symbol(arguments)
140
+ if name == "screener":
141
+ return await _screener(arguments)
142
+ if name == "technical_rating":
143
+ return await _technical_rating(arguments)
144
+ if name == "model_forecast":
145
+ return await _model_forecast(arguments)
146
+ return [TextContent(type="text", text=f"Unknown tool: {name}")]
147
+
148
+
149
+ async def _get_ohlcv(args: dict[str, Any]) -> list[TextContent]:
150
+ from ..data.client import get_ohlcv
151
+
152
+ df = await asyncio.to_thread(
153
+ get_ohlcv,
154
+ args["symbol"],
155
+ args.get("interval", "1D"),
156
+ args.get("n_bars", 500),
157
+ args.get("exchange"),
158
+ args.get("extended_session", False),
159
+ )
160
+ payload = {
161
+ "symbol": args["symbol"],
162
+ "interval": args.get("interval", "1D"),
163
+ "rows": len(df),
164
+ "index": [str(i) for i in df.index],
165
+ "columns": {c: df[c].tolist() for c in df.columns},
166
+ }
167
+ return [TextContent(type="text", text=json.dumps(payload, default=str))]
168
+
169
+
170
+ async def _search_symbol(args: dict[str, Any]) -> list[TextContent]:
171
+ from ..data.screener import search_symbol
172
+
173
+ results = await asyncio.to_thread(
174
+ search_symbol, args["query"], args.get("limit", 20)
175
+ )
176
+ return [TextContent(type="text", text=json.dumps(results, default=str))]
177
+
178
+
179
+ async def _screener(args: dict[str, Any]) -> list[TextContent]:
180
+ from ..data.screener import screener
181
+
182
+ filters_raw = args.get("filters") or []
183
+ filters = [(f[0], f[1], f[2]) for f in filters_raw]
184
+ order_by_raw = args.get("order_by")
185
+ order_by = (order_by_raw[0], bool(order_by_raw[1])) if order_by_raw else None
186
+
187
+ df = await asyncio.to_thread(
188
+ screener,
189
+ args.get("market", "america"),
190
+ args.get("columns"),
191
+ filters or None,
192
+ order_by,
193
+ args.get("limit", 50),
194
+ )
195
+ payload = {
196
+ "rows": len(df),
197
+ "columns": list(df.columns),
198
+ "data": df.to_dict(orient="records"),
199
+ }
200
+ return [TextContent(type="text", text=json.dumps(payload, default=str))]
201
+
202
+
203
+ async def _technical_rating(args: dict[str, Any]) -> list[TextContent]:
204
+ from ..data.screener import technical_rating
205
+
206
+ r = await asyncio.to_thread(
207
+ technical_rating, args["symbol"], args.get("interval", "1D")
208
+ )
209
+ return [TextContent(type="text", text=json.dumps(r, default=str))]
210
+
211
+
212
+ async def _model_forecast(args: dict[str, Any]) -> list[TextContent]:
213
+ from ..model.forecast import forecast_for_symbol
214
+
215
+ payload = await asyncio.to_thread(
216
+ forecast_for_symbol,
217
+ args["symbol"],
218
+ refresh=bool(args.get("refresh", False)),
219
+ period=args.get("period", "10y"),
220
+ )
221
+ return [TextContent(type="text", text=json.dumps(payload, default=str))]
222
+
223
+
224
+ # ─── Entry point ───────────────────────────────────────────────────────────
225
+
226
+
227
+ async def _run() -> None:
228
+ async with stdio_server() as (read_stream, write_stream):
229
+ await server.run(
230
+ read_stream, write_stream, server.create_initialization_options()
231
+ )
232
+
233
+
234
+ def main() -> None:
235
+ asyncio.run(_run())
236
+
237
+
238
+ if __name__ == "__main__":
239
+ main()
@@ -0,0 +1,19 @@
1
+ """Server-side stock-forecast model API helpers."""
2
+
3
+ from .forecast import (
4
+ DEFAULT_MODEL_ROOT,
5
+ DEFAULT_MODEL_REPO,
6
+ MODEL_UNIVERSE,
7
+ forecast_for_symbol,
8
+ model_status,
9
+ setup_model_env,
10
+ )
11
+
12
+ __all__ = [
13
+ "DEFAULT_MODEL_ROOT",
14
+ "DEFAULT_MODEL_REPO",
15
+ "MODEL_UNIVERSE",
16
+ "forecast_for_symbol",
17
+ "model_status",
18
+ "setup_model_env",
19
+ ]