tickflow-assist 0.2.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.
Files changed (246) hide show
  1. package/README.md +151 -0
  2. package/day_future.txt +8797 -0
  3. package/dist/analysis/orchestrators/composite-analysis.orchestrator.d.ts +35 -0
  4. package/dist/analysis/orchestrators/composite-analysis.orchestrator.js +232 -0
  5. package/dist/analysis/parsers/json-block.parser.d.ts +1 -0
  6. package/dist/analysis/parsers/json-block.parser.js +13 -0
  7. package/dist/analysis/parsers/key-levels.parser.d.ts +5 -0
  8. package/dist/analysis/parsers/key-levels.parser.js +61 -0
  9. package/dist/analysis/parsers/post-close-review.parser.d.ts +2 -0
  10. package/dist/analysis/parsers/post-close-review.parser.js +79 -0
  11. package/dist/analysis/parsers/watchlist-profile.parser.d.ts +6 -0
  12. package/dist/analysis/parsers/watchlist-profile.parser.js +93 -0
  13. package/dist/analysis/providers/financial-analysis.provider.d.ts +12 -0
  14. package/dist/analysis/providers/financial-analysis.provider.js +85 -0
  15. package/dist/analysis/providers/market-analysis.provider.d.ts +27 -0
  16. package/dist/analysis/providers/market-analysis.provider.js +187 -0
  17. package/dist/analysis/providers/news-analysis.provider.d.ts +9 -0
  18. package/dist/analysis/providers/news-analysis.provider.js +60 -0
  19. package/dist/analysis/tasks/analysis-step-task.d.ts +11 -0
  20. package/dist/analysis/tasks/analysis-step-task.js +1 -0
  21. package/dist/analysis/tasks/analysis-task.d.ts +13 -0
  22. package/dist/analysis/tasks/analysis-task.js +1 -0
  23. package/dist/analysis/tasks/composite-stock-analysis.task.d.ts +17 -0
  24. package/dist/analysis/tasks/composite-stock-analysis.task.js +47 -0
  25. package/dist/analysis/tasks/financial-fundamental-lite.task.d.ts +10 -0
  26. package/dist/analysis/tasks/financial-fundamental-lite.task.js +21 -0
  27. package/dist/analysis/tasks/financial-fundamental.task.d.ts +12 -0
  28. package/dist/analysis/tasks/financial-fundamental.task.js +64 -0
  29. package/dist/analysis/tasks/kline-technical-signal.task.d.ts +10 -0
  30. package/dist/analysis/tasks/kline-technical-signal.task.js +41 -0
  31. package/dist/analysis/tasks/kline-technical.task.d.ts +32 -0
  32. package/dist/analysis/tasks/kline-technical.task.js +61 -0
  33. package/dist/analysis/tasks/news-catalyst.task.d.ts +11 -0
  34. package/dist/analysis/tasks/news-catalyst.task.js +62 -0
  35. package/dist/analysis/tasks/post-close-review.task.d.ts +12 -0
  36. package/dist/analysis/tasks/post-close-review.task.js +35 -0
  37. package/dist/analysis/types/composite-analysis.d.ts +123 -0
  38. package/dist/analysis/types/composite-analysis.js +1 -0
  39. package/dist/background/daily-update.worker.d.ts +50 -0
  40. package/dist/background/daily-update.worker.js +546 -0
  41. package/dist/background/realtime-monitor.worker.d.ts +8 -0
  42. package/dist/background/realtime-monitor.worker.js +28 -0
  43. package/dist/bootstrap.d.ts +45 -0
  44. package/dist/bootstrap.js +214 -0
  45. package/dist/config/normalize.d.ts +4 -0
  46. package/dist/config/normalize.js +99 -0
  47. package/dist/config/schema.d.ts +23 -0
  48. package/dist/config/schema.js +18 -0
  49. package/dist/config/tickflow-access.d.ts +4 -0
  50. package/dist/config/tickflow-access.js +28 -0
  51. package/dist/constants/market-indexes.d.ts +5 -0
  52. package/dist/constants/market-indexes.js +4 -0
  53. package/dist/dev/run-daily-update-loop.d.ts +1 -0
  54. package/dist/dev/run-daily-update-loop.js +48 -0
  55. package/dist/dev/run-monitor-loop.d.ts +1 -0
  56. package/dist/dev/run-monitor-loop.js +60 -0
  57. package/dist/dev/run-tool.d.ts +1 -0
  58. package/dist/dev/run-tool.js +49 -0
  59. package/dist/dev/tickflow-assist-cli.d.ts +2 -0
  60. package/dist/dev/tickflow-assist-cli.js +525 -0
  61. package/dist/dev/validate-mx-search.d.ts +1 -0
  62. package/dist/dev/validate-mx-search.js +212 -0
  63. package/dist/plugin-commands.d.ts +3 -0
  64. package/dist/plugin-commands.js +229 -0
  65. package/dist/plugin.d.ts +8 -0
  66. package/dist/plugin.js +151 -0
  67. package/dist/prompts/analysis/common-system-prompt.d.ts +1 -0
  68. package/dist/prompts/analysis/common-system-prompt.js +44 -0
  69. package/dist/prompts/analysis/composite-analysis-user-prompt.d.ts +11 -0
  70. package/dist/prompts/analysis/composite-analysis-user-prompt.js +102 -0
  71. package/dist/prompts/analysis/financial-analysis-user-prompt.d.ts +7 -0
  72. package/dist/prompts/analysis/financial-analysis-user-prompt.js +106 -0
  73. package/dist/prompts/analysis/financial-lite-analysis-user-prompt.d.ts +7 -0
  74. package/dist/prompts/analysis/financial-lite-analysis-user-prompt.js +59 -0
  75. package/dist/prompts/analysis/index.d.ts +8 -0
  76. package/dist/prompts/analysis/index.js +8 -0
  77. package/dist/prompts/analysis/kline-analysis-user-prompt.d.ts +13 -0
  78. package/dist/prompts/analysis/kline-analysis-user-prompt.js +215 -0
  79. package/dist/prompts/analysis/news-analysis-user-prompt.d.ts +8 -0
  80. package/dist/prompts/analysis/news-analysis-user-prompt.js +57 -0
  81. package/dist/prompts/analysis/post-close-review-user-prompt.d.ts +3 -0
  82. package/dist/prompts/analysis/post-close-review-user-prompt.js +129 -0
  83. package/dist/prompts/analysis/watchlist-profile-extraction-prompt.d.ts +7 -0
  84. package/dist/prompts/analysis/watchlist-profile-extraction-prompt.js +52 -0
  85. package/dist/prompts/analysis-system-prompt.d.ts +1 -0
  86. package/dist/prompts/analysis-system-prompt.js +1 -0
  87. package/dist/prompts/analysis-user-prompt.d.ts +1 -0
  88. package/dist/prompts/analysis-user-prompt.js +1 -0
  89. package/dist/runtime/daily-update-process.d.ts +3 -0
  90. package/dist/runtime/daily-update-process.js +24 -0
  91. package/dist/runtime/monitor-process.d.ts +3 -0
  92. package/dist/runtime/monitor-process.js +24 -0
  93. package/dist/runtime/plugin-api.d.ts +22 -0
  94. package/dist/runtime/plugin-api.js +2 -0
  95. package/dist/runtime/process-config.d.ts +8 -0
  96. package/dist/runtime/process-config.js +35 -0
  97. package/dist/services/alert-service.d.ts +45 -0
  98. package/dist/services/alert-service.js +198 -0
  99. package/dist/services/analysis-service.d.ts +20 -0
  100. package/dist/services/analysis-service.js +73 -0
  101. package/dist/services/analysis-view-service.d.ts +23 -0
  102. package/dist/services/analysis-view-service.js +343 -0
  103. package/dist/services/financial-lite-service.d.ts +23 -0
  104. package/dist/services/financial-lite-service.js +201 -0
  105. package/dist/services/financial-service.d.ts +20 -0
  106. package/dist/services/financial-service.js +47 -0
  107. package/dist/services/indicator-service.d.ts +9 -0
  108. package/dist/services/indicator-service.js +67 -0
  109. package/dist/services/instrument-service.d.ts +6 -0
  110. package/dist/services/instrument-service.js +21 -0
  111. package/dist/services/key-level-service.d.ts +2 -0
  112. package/dist/services/key-level-service.js +2 -0
  113. package/dist/services/key-levels-backtest-service.d.ts +71 -0
  114. package/dist/services/key-levels-backtest-service.js +427 -0
  115. package/dist/services/kline-service.d.ts +19 -0
  116. package/dist/services/kline-service.js +91 -0
  117. package/dist/services/monitor-service.d.ts +44 -0
  118. package/dist/services/monitor-service.js +598 -0
  119. package/dist/services/mx-search-service.d.ts +22 -0
  120. package/dist/services/mx-search-service.js +286 -0
  121. package/dist/services/post-close-review-service.d.ts +31 -0
  122. package/dist/services/post-close-review-service.js +402 -0
  123. package/dist/services/quote-service.d.ts +7 -0
  124. package/dist/services/quote-service.js +9 -0
  125. package/dist/services/review-memory-service.d.ts +7 -0
  126. package/dist/services/review-memory-service.js +76 -0
  127. package/dist/services/tickflow-client.d.ts +43 -0
  128. package/dist/services/tickflow-client.js +126 -0
  129. package/dist/services/trading-calendar-service.d.ts +20 -0
  130. package/dist/services/trading-calendar-service.js +102 -0
  131. package/dist/services/update-service.d.ts +21 -0
  132. package/dist/services/update-service.js +130 -0
  133. package/dist/services/watchlist-profile-service.d.ts +20 -0
  134. package/dist/services/watchlist-profile-service.js +76 -0
  135. package/dist/services/watchlist-service.d.ts +43 -0
  136. package/dist/services/watchlist-service.js +204 -0
  137. package/dist/storage/db.d.ts +23 -0
  138. package/dist/storage/db.js +70 -0
  139. package/dist/storage/repositories/alert-log-repo.d.ts +15 -0
  140. package/dist/storage/repositories/alert-log-repo.js +54 -0
  141. package/dist/storage/repositories/analysis-log-repo.d.ts +8 -0
  142. package/dist/storage/repositories/analysis-log-repo.js +48 -0
  143. package/dist/storage/repositories/composite-analysis-repo.d.ts +9 -0
  144. package/dist/storage/repositories/composite-analysis-repo.js +116 -0
  145. package/dist/storage/repositories/financial-analysis-repo.d.ts +9 -0
  146. package/dist/storage/repositories/financial-analysis-repo.js +107 -0
  147. package/dist/storage/repositories/indicators-repo.d.ts +8 -0
  148. package/dist/storage/repositories/indicators-repo.js +98 -0
  149. package/dist/storage/repositories/intraday-klines-repo.d.ts +9 -0
  150. package/dist/storage/repositories/intraday-klines-repo.js +102 -0
  151. package/dist/storage/repositories/key-levels-history-repo.d.ts +9 -0
  152. package/dist/storage/repositories/key-levels-history-repo.js +91 -0
  153. package/dist/storage/repositories/key-levels-repo.d.ts +9 -0
  154. package/dist/storage/repositories/key-levels-repo.js +83 -0
  155. package/dist/storage/repositories/klines-repo.d.ts +8 -0
  156. package/dist/storage/repositories/klines-repo.js +60 -0
  157. package/dist/storage/repositories/news-analysis-repo.d.ts +9 -0
  158. package/dist/storage/repositories/news-analysis-repo.js +107 -0
  159. package/dist/storage/repositories/technical-analysis-repo.d.ts +9 -0
  160. package/dist/storage/repositories/technical-analysis-repo.js +80 -0
  161. package/dist/storage/repositories/watchlist-repo.d.ts +10 -0
  162. package/dist/storage/repositories/watchlist-repo.js +124 -0
  163. package/dist/storage/schemas.d.ts +13 -0
  164. package/dist/storage/schemas.js +177 -0
  165. package/dist/tools/add-stock.tool.d.ts +13 -0
  166. package/dist/tools/add-stock.tool.js +123 -0
  167. package/dist/tools/analyze.tool.d.ts +8 -0
  168. package/dist/tools/analyze.tool.js +24 -0
  169. package/dist/tools/backtest-key-levels.tool.d.ts +8 -0
  170. package/dist/tools/backtest-key-levels.tool.js +43 -0
  171. package/dist/tools/daily-update-status.tool.d.ts +6 -0
  172. package/dist/tools/daily-update-status.tool.js +9 -0
  173. package/dist/tools/fetch-financials.tool.d.ts +8 -0
  174. package/dist/tools/fetch-financials.tool.js +224 -0
  175. package/dist/tools/fetch-intraday-klines.tool.d.ts +11 -0
  176. package/dist/tools/fetch-intraday-klines.tool.js +58 -0
  177. package/dist/tools/fetch-klines.tool.d.ts +11 -0
  178. package/dist/tools/fetch-klines.tool.js +61 -0
  179. package/dist/tools/list-watchlist.tool.d.ts +6 -0
  180. package/dist/tools/list-watchlist.tool.js +22 -0
  181. package/dist/tools/monitor-status.tool.d.ts +6 -0
  182. package/dist/tools/monitor-status.tool.js +9 -0
  183. package/dist/tools/mx-search.tool.d.ts +8 -0
  184. package/dist/tools/mx-search.tool.js +77 -0
  185. package/dist/tools/mx-select-stock.tool.d.ts +8 -0
  186. package/dist/tools/mx-select-stock.tool.js +118 -0
  187. package/dist/tools/query-database.tool.d.ts +8 -0
  188. package/dist/tools/query-database.tool.js +283 -0
  189. package/dist/tools/refresh-watchlist-names.tool.d.ts +7 -0
  190. package/dist/tools/refresh-watchlist-names.tool.js +17 -0
  191. package/dist/tools/refresh-watchlist-profiles.tool.d.ts +9 -0
  192. package/dist/tools/refresh-watchlist-profiles.tool.js +67 -0
  193. package/dist/tools/remove-stock.tool.d.ts +9 -0
  194. package/dist/tools/remove-stock.tool.js +27 -0
  195. package/dist/tools/start-daily-update.tool.d.ts +10 -0
  196. package/dist/tools/start-daily-update.tool.js +23 -0
  197. package/dist/tools/start-monitor.tool.d.ts +9 -0
  198. package/dist/tools/start-monitor.tool.js +52 -0
  199. package/dist/tools/stop-daily-update.tool.d.ts +9 -0
  200. package/dist/tools/stop-daily-update.tool.js +20 -0
  201. package/dist/tools/stop-monitor.tool.d.ts +9 -0
  202. package/dist/tools/stop-monitor.tool.js +44 -0
  203. package/dist/tools/test-alert.tool.d.ts +7 -0
  204. package/dist/tools/test-alert.tool.js +21 -0
  205. package/dist/tools/update-all.tool.d.ts +9 -0
  206. package/dist/tools/update-all.tool.js +17 -0
  207. package/dist/tools/view-analysis.tool.d.ts +8 -0
  208. package/dist/tools/view-analysis.tool.js +95 -0
  209. package/dist/types/daily-update.d.ts +26 -0
  210. package/dist/types/daily-update.js +1 -0
  211. package/dist/types/domain.d.ts +140 -0
  212. package/dist/types/domain.js +1 -0
  213. package/dist/types/indicator.d.ts +43 -0
  214. package/dist/types/indicator.js +1 -0
  215. package/dist/types/monitor.d.ts +17 -0
  216. package/dist/types/monitor.js +1 -0
  217. package/dist/types/mx-search.d.ts +14 -0
  218. package/dist/types/mx-search.js +1 -0
  219. package/dist/types/mx-select-stock.d.ts +28 -0
  220. package/dist/types/mx-select-stock.js +1 -0
  221. package/dist/types/tickflow.d.ts +133 -0
  222. package/dist/types/tickflow.js +1 -0
  223. package/dist/utils/abortable-sleep.d.ts +1 -0
  224. package/dist/utils/abortable-sleep.js +20 -0
  225. package/dist/utils/china-time.d.ts +3 -0
  226. package/dist/utils/china-time.js +18 -0
  227. package/dist/utils/cost-price.d.ts +3 -0
  228. package/dist/utils/cost-price.js +18 -0
  229. package/dist/utils/format.d.ts +1 -0
  230. package/dist/utils/format.js +3 -0
  231. package/dist/utils/process.d.ts +5 -0
  232. package/dist/utils/process.js +1 -0
  233. package/dist/utils/symbol.d.ts +1 -0
  234. package/dist/utils/symbol.js +13 -0
  235. package/docs/installation.md +391 -0
  236. package/docs/usage.md +244 -0
  237. package/openclaw.plugin.json +116 -0
  238. package/package.json +57 -0
  239. package/python/indicator_runner.py +31 -0
  240. package/python/indicators.py +148 -0
  241. package/python/pyproject.toml +9 -0
  242. package/python/requirements.txt +3 -0
  243. package/python/uv.lock +366 -0
  244. package/skills/database-query/SKILL.md +58 -0
  245. package/skills/stock-analysis/SKILL.md +106 -0
  246. package/skills/usage-help/SKILL.md +102 -0
@@ -0,0 +1,214 @@
1
+ import { TickFlowClient } from "./services/tickflow-client.js";
2
+ import { InstrumentService } from "./services/instrument-service.js";
3
+ import { KlineService } from "./services/kline-service.js";
4
+ import { IndicatorService } from "./services/indicator-service.js";
5
+ import { FinancialService } from "./services/financial-service.js";
6
+ import { FinancialLiteService } from "./services/financial-lite-service.js";
7
+ import { MxApiService } from "./services/mx-search-service.js";
8
+ import { Database } from "./storage/db.js";
9
+ import { WatchlistRepository } from "./storage/repositories/watchlist-repo.js";
10
+ import { KlinesRepository } from "./storage/repositories/klines-repo.js";
11
+ import { IntradayKlinesRepository } from "./storage/repositories/intraday-klines-repo.js";
12
+ import { IndicatorsRepository } from "./storage/repositories/indicators-repo.js";
13
+ import { KeyLevelsRepository } from "./storage/repositories/key-levels-repo.js";
14
+ import { KeyLevelsHistoryRepository } from "./storage/repositories/key-levels-history-repo.js";
15
+ import { AnalysisLogRepository } from "./storage/repositories/analysis-log-repo.js";
16
+ import { AlertLogRepository } from "./storage/repositories/alert-log-repo.js";
17
+ import { TechnicalAnalysisRepository } from "./storage/repositories/technical-analysis-repo.js";
18
+ import { FinancialAnalysisRepository } from "./storage/repositories/financial-analysis-repo.js";
19
+ import { NewsAnalysisRepository } from "./storage/repositories/news-analysis-repo.js";
20
+ import { CompositeAnalysisRepository } from "./storage/repositories/composite-analysis-repo.js";
21
+ import { WatchlistService } from "./services/watchlist-service.js";
22
+ import { WatchlistProfileService } from "./services/watchlist-profile-service.js";
23
+ import { AnalysisService } from "./services/analysis-service.js";
24
+ import { AnalysisViewService } from "./services/analysis-view-service.js";
25
+ import { QuoteService } from "./services/quote-service.js";
26
+ import { TradingCalendarService } from "./services/trading-calendar-service.js";
27
+ import { MonitorService } from "./services/monitor-service.js";
28
+ import { AlertService } from "./services/alert-service.js";
29
+ import { UpdateService } from "./services/update-service.js";
30
+ import { KeyLevelsBacktestService } from "./services/key-levels-backtest-service.js";
31
+ import { PostCloseReviewService } from "./services/post-close-review-service.js";
32
+ import { ReviewMemoryService } from "./services/review-memory-service.js";
33
+ import { CompositeAnalysisOrchestrator } from "./analysis/orchestrators/composite-analysis.orchestrator.js";
34
+ import { MarketAnalysisProvider } from "./analysis/providers/market-analysis.provider.js";
35
+ import { FinancialAnalysisProvider } from "./analysis/providers/financial-analysis.provider.js";
36
+ import { NewsAnalysisProvider } from "./analysis/providers/news-analysis.provider.js";
37
+ import { KlineTechnicalSignalTask } from "./analysis/tasks/kline-technical-signal.task.js";
38
+ import { FinancialFundamentalTask } from "./analysis/tasks/financial-fundamental.task.js";
39
+ import { FinancialFundamentalLiteTask } from "./analysis/tasks/financial-fundamental-lite.task.js";
40
+ import { NewsCatalystTask } from "./analysis/tasks/news-catalyst.task.js";
41
+ import { CompositeStockAnalysisTask } from "./analysis/tasks/composite-stock-analysis.task.js";
42
+ import { PostCloseReviewTask } from "./analysis/tasks/post-close-review.task.js";
43
+ import { addStockTool } from "./tools/add-stock.tool.js";
44
+ import { analyzeTool } from "./tools/analyze.tool.js";
45
+ import { fetchKlinesTool } from "./tools/fetch-klines.tool.js";
46
+ import { fetchIntradayKlinesTool } from "./tools/fetch-intraday-klines.tool.js";
47
+ import { fetchFinancialsTool } from "./tools/fetch-financials.tool.js";
48
+ import { mxSearchTool } from "./tools/mx-search.tool.js";
49
+ import { mxSelectStockTool } from "./tools/mx-select-stock.tool.js";
50
+ import { listWatchlistTool } from "./tools/list-watchlist.tool.js";
51
+ import { dailyUpdateStatusTool } from "./tools/daily-update-status.tool.js";
52
+ import { monitorStatusTool } from "./tools/monitor-status.tool.js";
53
+ import { refreshWatchlistNamesTool } from "./tools/refresh-watchlist-names.tool.js";
54
+ import { refreshWatchlistProfilesTool } from "./tools/refresh-watchlist-profiles.tool.js";
55
+ import { queryDatabaseTool } from "./tools/query-database.tool.js";
56
+ import { removeStockTool } from "./tools/remove-stock.tool.js";
57
+ import { startDailyUpdateTool } from "./tools/start-daily-update.tool.js";
58
+ import { startMonitorTool } from "./tools/start-monitor.tool.js";
59
+ import { stopDailyUpdateTool } from "./tools/stop-daily-update.tool.js";
60
+ import { stopMonitorTool } from "./tools/stop-monitor.tool.js";
61
+ import { testAlertTool } from "./tools/test-alert.tool.js";
62
+ import { updateAllTool } from "./tools/update-all.tool.js";
63
+ import { viewAnalysisTool } from "./tools/view-analysis.tool.js";
64
+ import { backtestKeyLevelsTool } from "./tools/backtest-key-levels.tool.js";
65
+ import { RealtimeMonitorWorker } from "./background/realtime-monitor.worker.js";
66
+ import { DailyUpdateWorker } from "./background/daily-update.worker.js";
67
+ export function createAppContext(config, options = {}) {
68
+ const runtime = {
69
+ configSource: options.configSource ?? "local_config",
70
+ pluginManagedServices: options.pluginManagedServices ?? false,
71
+ openclawConfig: options.openclawConfig,
72
+ pluginRuntime: options.pluginRuntime,
73
+ };
74
+ const tickflowClient = new TickFlowClient(config.tickflowApiUrl, config.tickflowApiKey);
75
+ const database = new Database(config.databasePath);
76
+ const watchlistRepository = new WatchlistRepository(database);
77
+ const klinesRepository = new KlinesRepository(database);
78
+ const intradayKlinesRepository = new IntradayKlinesRepository(database);
79
+ const indicatorsRepository = new IndicatorsRepository(database);
80
+ const keyLevelsRepository = new KeyLevelsRepository(database);
81
+ const keyLevelsHistoryRepository = new KeyLevelsHistoryRepository(database);
82
+ const analysisLogRepository = new AnalysisLogRepository(database);
83
+ const alertLogRepository = new AlertLogRepository(database);
84
+ const technicalAnalysisRepository = new TechnicalAnalysisRepository(database);
85
+ const financialAnalysisRepository = new FinancialAnalysisRepository(database);
86
+ const newsAnalysisRepository = new NewsAnalysisRepository(database);
87
+ const compositeAnalysisRepository = new CompositeAnalysisRepository(database);
88
+ const instrumentService = new InstrumentService(tickflowClient);
89
+ const klineService = new KlineService(tickflowClient);
90
+ const quoteService = new QuoteService(tickflowClient);
91
+ const financialService = new FinancialService(tickflowClient);
92
+ const mxApiService = new MxApiService(config.mxSearchApiUrl, config.mxSearchApiKey);
93
+ const financialLiteService = new FinancialLiteService(mxApiService);
94
+ const analysisService = new AnalysisService(config.llmBaseUrl, config.llmApiKey, config.llmModel, analysisLogRepository);
95
+ const watchlistProfileService = new WatchlistProfileService(mxApiService, analysisService);
96
+ const tradingCalendarService = new TradingCalendarService(config.calendarFile);
97
+ const alertService = new AlertService({
98
+ openclawCliBin: config.openclawCliBin,
99
+ channel: config.alertChannel,
100
+ account: config.alertAccount,
101
+ target: config.alertTarget,
102
+ runtime: runtime.openclawConfig && runtime.pluginRuntime
103
+ ? {
104
+ config: runtime.openclawConfig,
105
+ runtime: runtime.pluginRuntime,
106
+ }
107
+ : undefined,
108
+ });
109
+ const indicatorService = new IndicatorService(config.pythonBin, config.pythonArgs, config.pythonWorkdir);
110
+ const watchlistService = new WatchlistService(watchlistRepository, instrumentService, watchlistProfileService);
111
+ const keyLevelsBacktestService = new KeyLevelsBacktestService(keyLevelsHistoryRepository, klinesRepository, intradayKlinesRepository, watchlistService);
112
+ const reviewMemoryService = new ReviewMemoryService(keyLevelsBacktestService);
113
+ const analysisViewService = new AnalysisViewService(analysisLogRepository, keyLevelsRepository, technicalAnalysisRepository, financialAnalysisRepository, newsAnalysisRepository, compositeAnalysisRepository);
114
+ const marketAnalysisProvider = new MarketAnalysisProvider(config.tickflowApiKeyLevel, watchlistService, klineService, quoteService, indicatorService, reviewMemoryService, tradingCalendarService, klinesRepository, intradayKlinesRepository, indicatorsRepository);
115
+ const financialAnalysisProvider = new FinancialAnalysisProvider(config.tickflowApiKeyLevel, financialService, financialLiteService);
116
+ const newsAnalysisProvider = new NewsAnalysisProvider(mxApiService);
117
+ const klineTechnicalSignalTask = new KlineTechnicalSignalTask();
118
+ const financialFundamentalTask = new FinancialFundamentalTask();
119
+ const financialFundamentalLiteTask = new FinancialFundamentalLiteTask();
120
+ const newsCatalystTask = new NewsCatalystTask();
121
+ const postCloseReviewTask = new PostCloseReviewTask();
122
+ const compositeStockAnalysisTask = new CompositeStockAnalysisTask(keyLevelsRepository, analysisLogRepository);
123
+ const compositeAnalysisOrchestrator = new CompositeAnalysisOrchestrator(analysisService, marketAnalysisProvider, financialAnalysisProvider, newsAnalysisProvider, klineTechnicalSignalTask, financialFundamentalTask, financialFundamentalLiteTask, newsCatalystTask, compositeStockAnalysisTask, technicalAnalysisRepository, financialAnalysisRepository, newsAnalysisRepository, compositeAnalysisRepository);
124
+ const monitorService = new MonitorService(config.databasePath, config.requestInterval, config.alertChannel, watchlistService, quoteService, tradingCalendarService, keyLevelsRepository, alertLogRepository, klinesRepository, alertService);
125
+ const updateService = new UpdateService(klineService, config.tickflowApiKeyLevel, indicatorService, klinesRepository, indicatorsRepository, intradayKlinesRepository, watchlistService, tradingCalendarService);
126
+ const postCloseReviewService = new PostCloseReviewService(watchlistService, compositeAnalysisOrchestrator, analysisService, postCloseReviewTask, keyLevelsRepository, keyLevelsHistoryRepository, klinesRepository, intradayKlinesRepository);
127
+ const realtimeMonitorWorker = new RealtimeMonitorWorker(monitorService, config.requestInterval * 1000);
128
+ const dailyUpdateWorker = new DailyUpdateWorker(updateService, postCloseReviewService, tradingCalendarService, config.databasePath, alertService, config.dailyUpdateNotify, runtime.configSource);
129
+ let managedLoopAbortController = null;
130
+ let managedLoopPromise = null;
131
+ return {
132
+ config,
133
+ tools: [
134
+ addStockTool(watchlistService, klineService, klinesRepository, indicatorService, indicatorsRepository),
135
+ analyzeTool(compositeAnalysisOrchestrator),
136
+ backtestKeyLevelsTool(keyLevelsBacktestService),
137
+ dailyUpdateStatusTool(dailyUpdateWorker, runtime.configSource),
138
+ fetchIntradayKlinesTool(config.tickflowApiKeyLevel, klineService, intradayKlinesRepository, tradingCalendarService),
139
+ fetchFinancialsTool(financialService),
140
+ fetchKlinesTool(klineService, klinesRepository, indicatorService, indicatorsRepository),
141
+ listWatchlistTool(watchlistService),
142
+ monitorStatusTool(monitorService),
143
+ mxSearchTool(mxApiService),
144
+ mxSelectStockTool(mxApiService),
145
+ queryDatabaseTool(database),
146
+ refreshWatchlistNamesTool(watchlistService),
147
+ refreshWatchlistProfilesTool(watchlistService),
148
+ removeStockTool(watchlistService),
149
+ startDailyUpdateTool(dailyUpdateWorker, config, runtime.configSource, runtime),
150
+ startMonitorTool(monitorService, runtime),
151
+ stopDailyUpdateTool(dailyUpdateWorker, runtime),
152
+ stopMonitorTool(monitorService, runtime),
153
+ testAlertTool(alertService),
154
+ updateAllTool(dailyUpdateWorker),
155
+ viewAnalysisTool(analysisViewService),
156
+ ],
157
+ backgroundServices: [
158
+ {
159
+ id: "tickflow-assist.managed-loop",
160
+ start: async () => {
161
+ if (managedLoopAbortController) {
162
+ return;
163
+ }
164
+ const abortController = new AbortController();
165
+ managedLoopAbortController = abortController;
166
+ await dailyUpdateWorker.bindManagedServiceRuntime(runtime.configSource);
167
+ await monitorService.bindManagedServiceRuntime();
168
+ managedLoopPromise = Promise.all([
169
+ dailyUpdateWorker
170
+ .runLoop(abortController.signal, "plugin_service", runtime.configSource)
171
+ .catch(() => { }),
172
+ realtimeMonitorWorker
173
+ .runLoop(abortController.signal, "plugin_service")
174
+ .catch(() => { }),
175
+ ]).then(() => undefined);
176
+ },
177
+ stop: async () => {
178
+ const abortController = managedLoopAbortController;
179
+ const runPromise = managedLoopPromise;
180
+ managedLoopAbortController = null;
181
+ managedLoopPromise = null;
182
+ if (!abortController) {
183
+ return;
184
+ }
185
+ abortController.abort();
186
+ await runPromise;
187
+ },
188
+ },
189
+ ],
190
+ runtime,
191
+ services: {
192
+ alertService,
193
+ monitorService,
194
+ realtimeMonitorWorker,
195
+ dailyUpdateWorker,
196
+ watchlistService,
197
+ database,
198
+ },
199
+ };
200
+ }
201
+ export async function buildWatchlistDebugSnapshot(app) {
202
+ const watchlistTableExists = await app.services.database.hasTable("watchlist");
203
+ const watchlistPreview = await app.services.watchlistService.list();
204
+ return {
205
+ databasePath: app.config.databasePath,
206
+ calendarFile: app.config.calendarFile,
207
+ requestInterval: app.config.requestInterval,
208
+ configSource: app.runtime.configSource,
209
+ pid: process.pid,
210
+ watchlistTableExists,
211
+ watchlistCount: watchlistPreview.length,
212
+ watchlistPreview: watchlistPreview.slice(0, 5),
213
+ };
214
+ }
@@ -0,0 +1,4 @@
1
+ import { type PluginConfig } from "./schema.js";
2
+ export declare function normalizePluginConfig(input: unknown): PluginConfig;
3
+ export declare function resolvePluginConfigPaths(config: PluginConfig, baseDir: string): PluginConfig;
4
+ export declare function validatePluginConfig(config: PluginConfig): string[];
@@ -0,0 +1,99 @@
1
+ import path from "node:path";
2
+ import { normalizeTickflowApiKeyLevel } from "./tickflow-access.js";
3
+ import { DEFAULT_PLUGIN_CONFIG } from "./schema.js";
4
+ function normalizeString(value, fallback = "") {
5
+ if (typeof value === "string") {
6
+ return value.trim();
7
+ }
8
+ if (value == null) {
9
+ return fallback;
10
+ }
11
+ return String(value).trim();
12
+ }
13
+ function normalizeInteger(value, fallback) {
14
+ const parsed = Number(value ?? fallback);
15
+ return Number.isFinite(parsed) ? Math.max(1, Math.trunc(parsed)) : fallback;
16
+ }
17
+ function normalizeStringArray(value, fallback) {
18
+ if (Array.isArray(value)) {
19
+ return value.map((item) => String(item).trim()).filter(Boolean);
20
+ }
21
+ return fallback;
22
+ }
23
+ function normalizeBoolean(value, fallback) {
24
+ if (typeof value === "boolean") {
25
+ return value;
26
+ }
27
+ if (typeof value === "string") {
28
+ const normalized = value.trim().toLowerCase();
29
+ if (["true", "1", "yes", "on"].includes(normalized)) {
30
+ return true;
31
+ }
32
+ if (["false", "0", "no", "off"].includes(normalized)) {
33
+ return false;
34
+ }
35
+ }
36
+ if (typeof value === "number") {
37
+ return value !== 0;
38
+ }
39
+ return fallback;
40
+ }
41
+ export function normalizePluginConfig(input) {
42
+ const raw = (input ?? {});
43
+ const envMxSearchApiUrl = normalizeString(process.env.MX_SEARCH_API_URL);
44
+ const envMxSearchApiKey = normalizeString(process.env.MX_APIKEY);
45
+ return {
46
+ tickflowApiUrl: normalizeString(raw.tickflowApiUrl, DEFAULT_PLUGIN_CONFIG.tickflowApiUrl),
47
+ tickflowApiKey: normalizeString(raw.tickflowApiKey),
48
+ tickflowApiKeyLevel: normalizeTickflowApiKeyLevel(raw.tickflowApiKeyLevel, DEFAULT_PLUGIN_CONFIG.tickflowApiKeyLevel),
49
+ mxSearchApiUrl: normalizeString(raw.mxSearchApiUrl, envMxSearchApiUrl || DEFAULT_PLUGIN_CONFIG.mxSearchApiUrl),
50
+ mxSearchApiKey: normalizeString(raw.mxSearchApiKey, envMxSearchApiKey || DEFAULT_PLUGIN_CONFIG.mxSearchApiKey),
51
+ llmBaseUrl: normalizeString(raw.llmBaseUrl, DEFAULT_PLUGIN_CONFIG.llmBaseUrl),
52
+ llmApiKey: normalizeString(raw.llmApiKey),
53
+ llmModel: normalizeString(raw.llmModel, DEFAULT_PLUGIN_CONFIG.llmModel),
54
+ databasePath: normalizeString(raw.databasePath, DEFAULT_PLUGIN_CONFIG.databasePath),
55
+ calendarFile: normalizeString(raw.calendarFile, DEFAULT_PLUGIN_CONFIG.calendarFile),
56
+ requestInterval: normalizeInteger(raw.requestInterval, DEFAULT_PLUGIN_CONFIG.requestInterval),
57
+ dailyUpdateNotify: normalizeBoolean(raw.dailyUpdateNotify, DEFAULT_PLUGIN_CONFIG.dailyUpdateNotify),
58
+ alertChannel: normalizeString(raw.alertChannel, DEFAULT_PLUGIN_CONFIG.alertChannel),
59
+ openclawCliBin: normalizeString(raw.openclawCliBin, DEFAULT_PLUGIN_CONFIG.openclawCliBin),
60
+ alertAccount: normalizeString(raw.alertAccount, DEFAULT_PLUGIN_CONFIG.alertAccount),
61
+ alertTarget: normalizeString(raw.alertTarget),
62
+ pythonBin: normalizeString(raw.pythonBin, DEFAULT_PLUGIN_CONFIG.pythonBin),
63
+ pythonArgs: normalizeStringArray(raw.pythonArgs, DEFAULT_PLUGIN_CONFIG.pythonArgs),
64
+ pythonWorkdir: normalizeString(raw.pythonWorkdir, DEFAULT_PLUGIN_CONFIG.pythonWorkdir),
65
+ };
66
+ }
67
+ export function resolvePluginConfigPaths(config, baseDir) {
68
+ return {
69
+ ...config,
70
+ databasePath: resolveConfigPath(config.databasePath, baseDir),
71
+ calendarFile: resolveConfigPath(config.calendarFile, baseDir),
72
+ pythonWorkdir: resolveConfigPath(config.pythonWorkdir, baseDir),
73
+ };
74
+ }
75
+ export function validatePluginConfig(config) {
76
+ const errors = [];
77
+ if (!config.tickflowApiKey) {
78
+ errors.push("tickflowApiKey is required");
79
+ }
80
+ if (!config.llmApiKey) {
81
+ errors.push("llmApiKey is required");
82
+ }
83
+ if (!config.alertTarget) {
84
+ errors.push("alertTarget is required");
85
+ }
86
+ if (!config.tickflowApiUrl.startsWith("http://") && !config.tickflowApiUrl.startsWith("https://")) {
87
+ errors.push("tickflowApiUrl must be an absolute http(s) URL");
88
+ }
89
+ if (config.requestInterval < 5) {
90
+ errors.push("requestInterval must be at least 5 seconds");
91
+ }
92
+ return errors;
93
+ }
94
+ function resolveConfigPath(value, baseDir) {
95
+ if (!value) {
96
+ return value;
97
+ }
98
+ return path.isAbsolute(value) ? value : path.resolve(baseDir, value);
99
+ }
@@ -0,0 +1,23 @@
1
+ import type { TickflowApiKeyLevel } from "./tickflow-access.js";
2
+ export interface PluginConfig {
3
+ tickflowApiUrl: string;
4
+ tickflowApiKey: string;
5
+ tickflowApiKeyLevel: TickflowApiKeyLevel;
6
+ mxSearchApiUrl: string;
7
+ mxSearchApiKey: string;
8
+ llmBaseUrl: string;
9
+ llmApiKey: string;
10
+ llmModel: string;
11
+ databasePath: string;
12
+ calendarFile: string;
13
+ requestInterval: number;
14
+ dailyUpdateNotify: boolean;
15
+ alertChannel: string;
16
+ openclawCliBin: string;
17
+ alertAccount: string;
18
+ alertTarget: string;
19
+ pythonBin: string;
20
+ pythonArgs: string[];
21
+ pythonWorkdir: string;
22
+ }
23
+ export declare const DEFAULT_PLUGIN_CONFIG: Omit<PluginConfig, "tickflowApiKey" | "llmApiKey" | "alertTarget">;
@@ -0,0 +1,18 @@
1
+ export const DEFAULT_PLUGIN_CONFIG = {
2
+ tickflowApiUrl: "https://api.tickflow.org",
3
+ tickflowApiKeyLevel: "free",
4
+ mxSearchApiUrl: "https://mkapi2.dfcfs.com/finskillshub/api/claw",
5
+ mxSearchApiKey: "",
6
+ llmBaseUrl: "https://api.openai.com/v1",
7
+ llmModel: "gpt-4o",
8
+ databasePath: "./data/lancedb",
9
+ calendarFile: "./day_future.txt",
10
+ requestInterval: 30,
11
+ dailyUpdateNotify: true,
12
+ alertChannel: "telegram",
13
+ openclawCliBin: "openclaw",
14
+ alertAccount: "",
15
+ pythonBin: "uv",
16
+ pythonArgs: ["run", "python"],
17
+ pythonWorkdir: "./python",
18
+ };
@@ -0,0 +1,4 @@
1
+ export type TickflowApiKeyLevel = "free" | "start" | "pro" | "expert";
2
+ export declare function normalizeTickflowApiKeyLevel(value: unknown, fallback?: TickflowApiKeyLevel): TickflowApiKeyLevel;
3
+ export declare function supportsIntradayKlines(level: TickflowApiKeyLevel): boolean;
4
+ export declare function formatTickflowApiKeyLevel(level: TickflowApiKeyLevel): string;
@@ -0,0 +1,28 @@
1
+ const INTRADAY_ENABLED_LEVELS = new Set(["pro", "expert"]);
2
+ export function normalizeTickflowApiKeyLevel(value, fallback = "free") {
3
+ const normalized = String(value ?? "")
4
+ .trim()
5
+ .toLowerCase();
6
+ if (normalized === "export") {
7
+ return "expert";
8
+ }
9
+ if (normalized === "free" || normalized === "start" || normalized === "pro" || normalized === "expert") {
10
+ return normalized;
11
+ }
12
+ return fallback;
13
+ }
14
+ export function supportsIntradayKlines(level) {
15
+ return INTRADAY_ENABLED_LEVELS.has(level);
16
+ }
17
+ export function formatTickflowApiKeyLevel(level) {
18
+ switch (level) {
19
+ case "free":
20
+ return "Free";
21
+ case "start":
22
+ return "Start";
23
+ case "pro":
24
+ return "Pro";
25
+ case "expert":
26
+ return "Expert";
27
+ }
28
+ }
@@ -0,0 +1,5 @@
1
+ export interface MarketIndexSpec {
2
+ symbol: string;
3
+ name: string;
4
+ }
5
+ export declare const DEFAULT_MARKET_INDEXES: MarketIndexSpec[];
@@ -0,0 +1,4 @@
1
+ export const DEFAULT_MARKET_INDEXES = [
2
+ { symbol: "000001.SH", name: "上证指数" },
3
+ { symbol: "399001.SZ", name: "深证成指" },
4
+ ];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,48 @@
1
+ import { createAppContext } from "../bootstrap.js";
2
+ import { loadProcessConfig } from "../runtime/process-config.js";
3
+ async function main() {
4
+ const { config, configSource } = await loadProcessConfig();
5
+ const app = createAppContext(config, { configSource });
6
+ const worker = app.services.dailyUpdateWorker;
7
+ const alertService = app.services.alertService;
8
+ await worker.markSchedulerRunning(process.pid, configSource);
9
+ process.stdout.write("TickFlow daily update loop started\n");
10
+ const controller = new AbortController();
11
+ const shutdown = async (signal) => {
12
+ controller.abort();
13
+ const state = await worker.getState();
14
+ const isCurrentWorker = state.workerPid === process.pid;
15
+ await worker.markSchedulerStopped();
16
+ if (isCurrentWorker && state.running && !state.expectedStop) {
17
+ await alertService.send(alertService.formatSystemNotification("⚠️ TickFlow 日更退出通知", [
18
+ `时间: ${new Date().toISOString()}`,
19
+ `原因: 收到信号 ${signal}`,
20
+ ]));
21
+ }
22
+ process.exit(0);
23
+ };
24
+ process.on("SIGINT", () => void shutdown("SIGINT"));
25
+ process.on("SIGTERM", () => void shutdown("SIGTERM"));
26
+ try {
27
+ await worker.runLoop(controller.signal);
28
+ }
29
+ catch (error) {
30
+ const message = error instanceof Error ? error.message : String(error);
31
+ const state = await worker.getState();
32
+ const isCurrentWorker = state.workerPid === process.pid;
33
+ await worker.markSchedulerStopped();
34
+ if (isCurrentWorker) {
35
+ await alertService.send(alertService.formatSystemNotification("⚠️ TickFlow 日更退出通知", [
36
+ `时间: ${new Date().toISOString()}`,
37
+ "原因: 日更循环异常退出",
38
+ `详情: ${message}`,
39
+ ]));
40
+ }
41
+ throw error;
42
+ }
43
+ }
44
+ void main().catch((error) => {
45
+ const message = error instanceof Error ? error.stack ?? error.message : String(error);
46
+ process.stderr.write(`${message}\n`);
47
+ process.exitCode = 1;
48
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,60 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { createAppContext } from "../bootstrap.js";
4
+ import { normalizePluginConfig, resolvePluginConfigPaths } from "../config/normalize.js";
5
+ async function main() {
6
+ const config = await loadLocalConfig();
7
+ const app = createAppContext(config, { configSource: "local_config" });
8
+ const worker = app.services.realtimeMonitorWorker;
9
+ const alertService = app.services.alertService;
10
+ const monitorService = app.services.monitorService;
11
+ await monitorService.recordHeartbeat("fallback_process");
12
+ await monitorService.setWorkerPid(process.pid);
13
+ process.stdout.write(`TickFlow monitor loop started, interval=${config.requestInterval}s\n`);
14
+ const controller = new AbortController();
15
+ const shutdown = async (signal) => {
16
+ controller.abort();
17
+ const state = await monitorService.getState();
18
+ const isCurrentWorker = state.workerPid === process.pid;
19
+ await monitorService.setWorkerPid(null);
20
+ if (isCurrentWorker && state.running && !state.expectedStop) {
21
+ await alertService.send(alertService.formatSystemNotification("⚠️ TickFlow 监控退出通知", [
22
+ `时间: ${new Date().toISOString()}`,
23
+ `原因: 收到信号 ${signal}`,
24
+ ]));
25
+ }
26
+ await monitorService.setExpectedStop(false);
27
+ process.exit(0);
28
+ };
29
+ process.on("SIGINT", () => void shutdown("SIGINT"));
30
+ process.on("SIGTERM", () => void shutdown("SIGTERM"));
31
+ try {
32
+ await worker.runLoop(controller.signal, "fallback_process");
33
+ }
34
+ catch (error) {
35
+ const message = error instanceof Error ? error.message : String(error);
36
+ const state = await monitorService.getState();
37
+ const isCurrentWorker = state.workerPid === process.pid;
38
+ await monitorService.setWorkerPid(null);
39
+ await monitorService.setExpectedStop(false);
40
+ if (isCurrentWorker) {
41
+ await alertService.send(alertService.formatSystemNotification("⚠️ TickFlow 监控退出通知", [
42
+ `时间: ${new Date().toISOString()}`,
43
+ "原因: 监控循环异常退出",
44
+ `详情: ${message}`,
45
+ ]));
46
+ }
47
+ throw error;
48
+ }
49
+ }
50
+ async function loadLocalConfig() {
51
+ const configPath = path.resolve("local.config.json");
52
+ const raw = await readFile(configPath, "utf-8");
53
+ const parsed = JSON.parse(raw);
54
+ return resolvePluginConfigPaths(normalizePluginConfig(parsed.plugin ?? {}), process.cwd());
55
+ }
56
+ void main().catch((error) => {
57
+ const message = error instanceof Error ? error.stack ?? error.message : String(error);
58
+ process.stderr.write(`${message}\n`);
59
+ process.exitCode = 1;
60
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,49 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { createAppContext } from "../bootstrap.js";
4
+ import { normalizePluginConfig, resolvePluginConfigPaths } from "../config/normalize.js";
5
+ async function main() {
6
+ const [, , toolName, ...rest] = process.argv;
7
+ if (!toolName) {
8
+ throw new Error("usage: npm run tool -- <tool-name> [json-or-plain-args]");
9
+ }
10
+ const config = await loadLocalConfig();
11
+ const app = createAppContext(config, { configSource: "local_config" });
12
+ const normalizedToolName = normalizeToolName(toolName);
13
+ const tool = app.tools.find((entry) => entry.name === normalizedToolName);
14
+ if (!tool) {
15
+ throw new Error(`tool not found: ${toolName}`);
16
+ }
17
+ const rawInput = parseToolInput(rest);
18
+ const output = await tool.run({ rawInput });
19
+ process.stdout.write(`${output}\n`);
20
+ }
21
+ async function loadLocalConfig() {
22
+ const configPath = path.resolve("local.config.json");
23
+ const raw = await readFile(configPath, "utf-8");
24
+ const parsed = JSON.parse(raw);
25
+ return resolvePluginConfigPaths(normalizePluginConfig(parsed.plugin ?? {}), process.cwd());
26
+ }
27
+ function parseToolInput(args) {
28
+ if (args.length === 0) {
29
+ return undefined;
30
+ }
31
+ const joined = args.join(" ").trim();
32
+ if (!joined) {
33
+ return undefined;
34
+ }
35
+ try {
36
+ return JSON.parse(joined);
37
+ }
38
+ catch {
39
+ return joined;
40
+ }
41
+ }
42
+ function normalizeToolName(name) {
43
+ return name.replace(/-/g, "_");
44
+ }
45
+ void main().catch((error) => {
46
+ const message = error instanceof Error ? error.message : String(error);
47
+ process.stderr.write(`${message}\n`);
48
+ process.exitCode = 1;
49
+ });
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};