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,73 @@
1
+ export class AnalysisService {
2
+ llmBaseUrl;
3
+ llmApiKey;
4
+ llmModel;
5
+ analysisLogRepository;
6
+ constructor(llmBaseUrl, llmApiKey, llmModel, analysisLogRepository) {
7
+ this.llmBaseUrl = llmBaseUrl;
8
+ this.llmApiKey = llmApiKey;
9
+ this.llmModel = llmModel;
10
+ this.analysisLogRepository = analysisLogRepository;
11
+ }
12
+ isConfigured() {
13
+ return Boolean(this.llmBaseUrl.trim() && this.llmApiKey.trim() && this.llmModel.trim());
14
+ }
15
+ getConfigurationError() {
16
+ if (!this.llmBaseUrl.trim()) {
17
+ return "LLM 未配置接口地址,请设置 llmBaseUrl";
18
+ }
19
+ if (!this.llmApiKey.trim()) {
20
+ return "LLM 未配置 API Key,请设置 llmApiKey";
21
+ }
22
+ if (!this.llmModel.trim()) {
23
+ return "LLM 未配置模型,请设置 llmModel";
24
+ }
25
+ return null;
26
+ }
27
+ async runTask(task, input) {
28
+ const prepared = await task.prepare(input);
29
+ const analysisText = await this.generateText(prepared.systemPrompt, prepared.userPrompt);
30
+ const result = await task.parseResult(analysisText, input);
31
+ await task.persistResult(result, input);
32
+ return result;
33
+ }
34
+ async generateText(systemPrompt, userPrompt, options = {}) {
35
+ return this.callLlm(systemPrompt, userPrompt, options);
36
+ }
37
+ async getLatestAnalysis(symbol) {
38
+ return this.analysisLogRepository.getLatest(symbol);
39
+ }
40
+ async callLlm(systemPrompt, userPrompt, options) {
41
+ const configError = this.getConfigurationError();
42
+ if (configError) {
43
+ throw new Error(configError);
44
+ }
45
+ const url = new URL("/chat/completions", this.llmBaseUrl).toString();
46
+ const response = await fetch(url, {
47
+ method: "POST",
48
+ headers: {
49
+ "Content-Type": "application/json",
50
+ Authorization: `Bearer ${this.llmApiKey}`,
51
+ },
52
+ body: JSON.stringify({
53
+ model: this.llmModel,
54
+ messages: [
55
+ { role: "system", content: systemPrompt },
56
+ { role: "user", content: userPrompt },
57
+ ],
58
+ max_tokens: options.maxTokens ?? 4096,
59
+ temperature: options.temperature ?? 0.3,
60
+ }),
61
+ });
62
+ if (!response.ok) {
63
+ const text = await response.text();
64
+ throw new Error(`LLM analyze request failed: ${response.status} ${response.statusText} ${text}`);
65
+ }
66
+ const json = (await response.json());
67
+ const content = json.choices?.[0]?.message?.content?.trim();
68
+ if (!content) {
69
+ throw new Error("LLM analyze response content is empty");
70
+ }
71
+ return content;
72
+ }
73
+ }
@@ -0,0 +1,23 @@
1
+ import { AnalysisLogRepository } from "../storage/repositories/analysis-log-repo.js";
2
+ import { CompositeAnalysisRepository } from "../storage/repositories/composite-analysis-repo.js";
3
+ import { FinancialAnalysisRepository } from "../storage/repositories/financial-analysis-repo.js";
4
+ import { KeyLevelsRepository } from "../storage/repositories/key-levels-repo.js";
5
+ import { NewsAnalysisRepository } from "../storage/repositories/news-analysis-repo.js";
6
+ import { TechnicalAnalysisRepository } from "../storage/repositories/technical-analysis-repo.js";
7
+ export type AnalysisViewProfile = "composite" | "technical" | "financial" | "news" | "all";
8
+ export declare class AnalysisViewService {
9
+ private readonly analysisLogRepository;
10
+ private readonly keyLevelsRepository;
11
+ private readonly technicalAnalysisRepository;
12
+ private readonly financialAnalysisRepository;
13
+ private readonly newsAnalysisRepository;
14
+ private readonly compositeAnalysisRepository;
15
+ constructor(analysisLogRepository: AnalysisLogRepository, keyLevelsRepository: KeyLevelsRepository, technicalAnalysisRepository: TechnicalAnalysisRepository, financialAnalysisRepository: FinancialAnalysisRepository, newsAnalysisRepository: NewsAnalysisRepository, compositeAnalysisRepository: CompositeAnalysisRepository);
16
+ render(symbol: string, profile: AnalysisViewProfile, limit?: number): Promise<string>;
17
+ private renderComposite;
18
+ private renderTechnical;
19
+ private renderFinancial;
20
+ private renderNews;
21
+ private renderAll;
22
+ private getLegacyComposite;
23
+ }
@@ -0,0 +1,343 @@
1
+ export class AnalysisViewService {
2
+ analysisLogRepository;
3
+ keyLevelsRepository;
4
+ technicalAnalysisRepository;
5
+ financialAnalysisRepository;
6
+ newsAnalysisRepository;
7
+ compositeAnalysisRepository;
8
+ constructor(analysisLogRepository, keyLevelsRepository, technicalAnalysisRepository, financialAnalysisRepository, newsAnalysisRepository, compositeAnalysisRepository) {
9
+ this.analysisLogRepository = analysisLogRepository;
10
+ this.keyLevelsRepository = keyLevelsRepository;
11
+ this.technicalAnalysisRepository = technicalAnalysisRepository;
12
+ this.financialAnalysisRepository = financialAnalysisRepository;
13
+ this.newsAnalysisRepository = newsAnalysisRepository;
14
+ this.compositeAnalysisRepository = compositeAnalysisRepository;
15
+ }
16
+ async render(symbol, profile, limit = 1) {
17
+ const normalizedLimit = Math.max(1, Math.trunc(limit));
18
+ switch (profile) {
19
+ case "technical":
20
+ return this.renderTechnical(symbol, normalizedLimit);
21
+ case "financial":
22
+ return this.renderFinancial(symbol, normalizedLimit);
23
+ case "news":
24
+ return this.renderNews(symbol, normalizedLimit);
25
+ case "all":
26
+ return this.renderAll(symbol, normalizedLimit);
27
+ case "composite":
28
+ default:
29
+ return this.renderComposite(symbol, normalizedLimit);
30
+ }
31
+ }
32
+ async renderComposite(symbol, limit) {
33
+ const entries = await this.compositeAnalysisRepository.listLatest(symbol, limit);
34
+ if (entries.length > 0) {
35
+ return renderEntryCollection(symbol, "综合分析", entries, formatCompositeEntry, limit);
36
+ }
37
+ const legacy = await this.getLegacyComposite(symbol);
38
+ if (!legacy) {
39
+ return `⚠️ 暂无 ${symbol} 的综合分析记录`;
40
+ }
41
+ if (limit > 1) {
42
+ return [
43
+ `🗂️ 最近 ${limit} 次综合分析: ${symbol}`,
44
+ "返回记录: 1",
45
+ "说明: 当前仅存在 legacy 综合分析记录,历史列表从第二阶段结果表开始累计。",
46
+ "",
47
+ formatLegacyCompositeEntry(symbol, legacy),
48
+ ].join("\n");
49
+ }
50
+ return formatLegacyCompositeEntry(symbol, legacy);
51
+ }
52
+ async renderTechnical(symbol, limit) {
53
+ const entries = await this.technicalAnalysisRepository.listLatest(symbol, limit);
54
+ if (entries.length > 0) {
55
+ return renderEntryCollection(symbol, "技术面分析", entries, formatTechnicalEntry, limit);
56
+ }
57
+ const legacy = await this.getLegacyComposite(symbol);
58
+ if (!legacy) {
59
+ return `⚠️ 暂无 ${symbol} 的技术面分析记录`;
60
+ }
61
+ if (limit > 1) {
62
+ return [
63
+ `🗂️ 最近 ${limit} 次技术面分析: ${symbol}`,
64
+ "返回记录: 1",
65
+ "说明: 当前仅存在 legacy 技术面记录,历史列表从第二阶段结果表开始累计。",
66
+ "",
67
+ formatLegacyTechnicalEntry(symbol, legacy),
68
+ ].join("\n");
69
+ }
70
+ return formatLegacyTechnicalEntry(symbol, legacy);
71
+ }
72
+ async renderFinancial(symbol, limit) {
73
+ const entries = await this.financialAnalysisRepository.listLatest(symbol, limit);
74
+ if (entries.length === 0) {
75
+ return `⚠️ 暂无 ${symbol} 的基本面分析记录`;
76
+ }
77
+ return renderEntryCollection(symbol, "基本面分析", entries, formatFinancialEntry, limit);
78
+ }
79
+ async renderNews(symbol, limit) {
80
+ const entries = await this.newsAnalysisRepository.listLatest(symbol, limit);
81
+ if (entries.length === 0) {
82
+ return `⚠️ 暂无 ${symbol} 的资讯面分析记录`;
83
+ }
84
+ return renderEntryCollection(symbol, "资讯面分析", entries, formatNewsEntry, limit);
85
+ }
86
+ async renderAll(symbol, limit) {
87
+ const [composite, technical, financial, news] = await Promise.all([
88
+ this.compositeAnalysisRepository.listLatest(symbol, limit),
89
+ this.technicalAnalysisRepository.listLatest(symbol, limit),
90
+ this.financialAnalysisRepository.listLatest(symbol, limit),
91
+ this.newsAnalysisRepository.listLatest(symbol, limit),
92
+ ]);
93
+ const legacy = composite.length === 0 || technical.length === 0
94
+ ? await this.getLegacyComposite(symbol)
95
+ : null;
96
+ const sections = [
97
+ composite.length > 0
98
+ ? renderEntryCollection(symbol, "综合分析", composite, formatCompositeEntry, limit)
99
+ : formatLegacyOrEmptyComposite(symbol, legacy, limit),
100
+ technical.length > 0
101
+ ? renderEntryCollection(symbol, "技术面分析", technical, formatTechnicalEntry, limit)
102
+ : formatLegacyOrEmptyTechnical(symbol, legacy, limit),
103
+ financial.length > 0
104
+ ? renderEntryCollection(symbol, "基本面分析", financial, formatFinancialEntry, limit)
105
+ : `⚠️ 暂无 ${symbol} 的基本面分析记录`,
106
+ news.length > 0
107
+ ? renderEntryCollection(symbol, "资讯面分析", news, formatNewsEntry, limit)
108
+ : `⚠️ 暂无 ${symbol} 的资讯面分析记录`,
109
+ ];
110
+ return sections.join("\n\n====================\n\n");
111
+ }
112
+ async getLegacyComposite(symbol) {
113
+ const [analysisLog, keyLevels] = await Promise.all([
114
+ this.analysisLogRepository.getLatest(symbol),
115
+ this.keyLevelsRepository.getBySymbol(symbol),
116
+ ]);
117
+ if (!analysisLog) {
118
+ return null;
119
+ }
120
+ return {
121
+ analysis_date: analysisLog.analysis_date,
122
+ analysis_text: analysisLog.analysis_text,
123
+ structured_ok: analysisLog.structured_ok,
124
+ levels: keyLevels && keyLevels.symbol === symbol ? keyLevels : null,
125
+ };
126
+ }
127
+ }
128
+ function formatCompositeEntry(symbol, entry) {
129
+ const lines = [
130
+ `📝 最近一次综合分析: ${symbol}`,
131
+ `日期: ${entry.analysis_date}`,
132
+ `结构化解析: ${entry.structured_ok ? "成功" : "失败"}`,
133
+ renderScoreLine("综合评分", entry.score),
134
+ renderScoreLine("技术面评分", entry.technical_score),
135
+ renderScoreLine("基本面评分", entry.financial_score),
136
+ renderScoreLine("资讯面评分", entry.news_score),
137
+ `财务倾向: ${renderBias(entry.financial_bias)}`,
138
+ `资讯倾向: ${renderBias(entry.news_bias)}`,
139
+ ];
140
+ if (entry.evidence.financial_mode && entry.evidence.financial_mode !== "none") {
141
+ lines.push(`基本面模式: ${entry.evidence.financial_mode}${entry.evidence.financial_source ? ` | 来源=${entry.evidence.financial_source}` : ""}`);
142
+ }
143
+ if (entry.evidence.financial_latest_period_end) {
144
+ lines.push(`最新财报期: ${entry.evidence.financial_latest_period_end}`);
145
+ }
146
+ else if (entry.evidence.financial_lite_as_of) {
147
+ lines.push(`指标日期: ${entry.evidence.financial_lite_as_of}`);
148
+ }
149
+ if (entry.evidence.news_query) {
150
+ lines.push(`资讯检索: ${entry.evidence.news_query}`);
151
+ }
152
+ lines.push(`资讯条数: ${entry.evidence.news_source_count}`);
153
+ lines.push(...renderLevels(entry));
154
+ lines.push("", entry.analysis_text);
155
+ return lines.join("\n");
156
+ }
157
+ function formatTechnicalEntry(symbol, entry) {
158
+ const lines = [
159
+ `📝 最近一次技术面分析: ${symbol}`,
160
+ `日期: ${entry.analysis_date}`,
161
+ `结构化解析: ${entry.structured_ok ? "成功" : "失败"}`,
162
+ renderScoreLine("技术面评分", entry.score),
163
+ ...renderLevels(entry),
164
+ "",
165
+ entry.analysis_text,
166
+ ];
167
+ return lines.join("\n");
168
+ }
169
+ function formatFinancialEntry(symbol, entry) {
170
+ const lines = [
171
+ `📝 最近一次基本面分析: ${symbol}`,
172
+ `日期: ${entry.analysis_date}`,
173
+ renderScoreLine("基本面评分", entry.score),
174
+ `基本面倾向: ${renderBias(entry.bias)}`,
175
+ ];
176
+ if (entry.evidence.mode && entry.evidence.mode !== "none") {
177
+ lines.push(`分析模式: ${entry.evidence.mode}${entry.evidence.source ? ` | 来源=${entry.evidence.source}` : ""}`);
178
+ }
179
+ if (entry.evidence.latest_period_end) {
180
+ lines.push(`最新财报期: ${entry.evidence.latest_period_end}`);
181
+ }
182
+ else if (entry.evidence.lite_as_of) {
183
+ lines.push(`指标日期: ${entry.evidence.lite_as_of}`);
184
+ }
185
+ if (entry.evidence.latest_announce_date) {
186
+ lines.push(`公告日期: ${entry.evidence.latest_announce_date}`);
187
+ }
188
+ if (entry.evidence.mode === "lite") {
189
+ lines.push(`指标覆盖: ${entry.evidence.lite_metric_count ?? 0}${entry.evidence.lite_metric_labels && entry.evidence.lite_metric_labels.length > 0 ? ` | ${entry.evidence.lite_metric_labels.join(" / ")}` : ""}`);
190
+ if (entry.evidence.lite_query) {
191
+ lines.push(`拖底检索: ${entry.evidence.lite_query}`);
192
+ }
193
+ }
194
+ else {
195
+ lines.push(`数据覆盖: income=${entry.evidence.income_count}, metrics=${entry.evidence.metrics_count}, cash_flow=${entry.evidence.cash_flow_count}, balance_sheet=${entry.evidence.balance_sheet_count}`);
196
+ }
197
+ if (entry.evidence.note) {
198
+ lines.push(`备注: ${entry.evidence.note}`);
199
+ }
200
+ lines.push(...renderStringSection("优势", entry.strengths));
201
+ lines.push(...renderStringSection("风险", entry.risks));
202
+ lines.push(...renderStringSection("关注点", entry.watch_items));
203
+ lines.push("", entry.analysis_text);
204
+ return lines.join("\n");
205
+ }
206
+ function formatNewsEntry(symbol, entry) {
207
+ const lines = [
208
+ `📝 最近一次资讯面分析: ${symbol}`,
209
+ `日期: ${entry.analysis_date}`,
210
+ renderScoreLine("资讯面评分", entry.score),
211
+ `资讯倾向: ${renderBias(entry.bias)}`,
212
+ `检索问句: ${entry.query}`,
213
+ `资讯条数: ${entry.source_count}`,
214
+ ];
215
+ lines.push(...renderStringSection("催化因素", entry.catalysts));
216
+ lines.push(...renderStringSection("风险因素", entry.risks));
217
+ lines.push(...renderStringSection("跟踪要点", entry.watch_items));
218
+ if (entry.evidence.documents.length > 0) {
219
+ lines.push("证据快照:");
220
+ entry.evidence.documents.forEach((document, index) => {
221
+ const parts = [document.title];
222
+ if (document.published_at) {
223
+ parts.push(document.published_at);
224
+ }
225
+ if (document.source) {
226
+ parts.push(document.source);
227
+ }
228
+ lines.push(`${index + 1}. ${parts.join(" | ")}`);
229
+ });
230
+ }
231
+ lines.push("", entry.analysis_text);
232
+ return lines.join("\n");
233
+ }
234
+ function formatLegacyCompositeEntry(symbol, entry) {
235
+ const lines = [
236
+ `📝 最近一次综合分析: ${symbol}`,
237
+ `日期: ${entry.analysis_date}`,
238
+ `结构化解析: ${entry.structured_ok ? "成功" : "失败"}`,
239
+ "来源: legacy analysis_log",
240
+ ...renderLevels(entry.levels),
241
+ "",
242
+ entry.analysis_text,
243
+ ];
244
+ return lines.join("\n");
245
+ }
246
+ function formatLegacyTechnicalEntry(symbol, entry) {
247
+ const lines = [
248
+ `📝 最近一次技术面分析: ${symbol}`,
249
+ `日期: ${entry.analysis_date}`,
250
+ `结构化解析: ${entry.structured_ok ? "成功" : "失败"}`,
251
+ "来源: legacy key_levels/analysis_log",
252
+ ...renderLevels(entry.levels),
253
+ "",
254
+ entry.analysis_text,
255
+ ];
256
+ return lines.join("\n");
257
+ }
258
+ function formatLegacyOrEmptyComposite(symbol, legacy, limit = 1) {
259
+ if (!legacy) {
260
+ return `⚠️ 暂无 ${symbol} 的综合分析记录`;
261
+ }
262
+ if (limit > 1) {
263
+ return [
264
+ `🗂️ 最近 ${limit} 次综合分析: ${symbol}`,
265
+ "返回记录: 1",
266
+ "说明: 当前仅存在 legacy 综合分析记录,历史列表从第二阶段结果表开始累计。",
267
+ "",
268
+ formatLegacyCompositeEntry(symbol, legacy),
269
+ ].join("\n");
270
+ }
271
+ return formatLegacyCompositeEntry(symbol, legacy);
272
+ }
273
+ function formatLegacyOrEmptyTechnical(symbol, legacy, limit = 1) {
274
+ if (!legacy) {
275
+ return `⚠️ 暂无 ${symbol} 的技术面分析记录`;
276
+ }
277
+ if (limit > 1) {
278
+ return [
279
+ `🗂️ 最近 ${limit} 次技术面分析: ${symbol}`,
280
+ "返回记录: 1",
281
+ "说明: 当前仅存在 legacy 技术面记录,历史列表从第二阶段结果表开始累计。",
282
+ "",
283
+ formatLegacyTechnicalEntry(symbol, legacy),
284
+ ].join("\n");
285
+ }
286
+ return formatLegacyTechnicalEntry(symbol, legacy);
287
+ }
288
+ function renderEntryCollection(symbol, title, entries, formatter, requestedLimit) {
289
+ if (entries.length === 1 && requestedLimit <= 1) {
290
+ return formatter(symbol, entries[0]);
291
+ }
292
+ const sections = entries.map((entry, index) => [`[${index + 1}]`, formatter(symbol, entry)].join("\n"));
293
+ return [
294
+ `🗂️ 最近 ${requestedLimit} 次${title}: ${symbol}`,
295
+ `返回记录: ${entries.length}`,
296
+ "",
297
+ sections.join("\n\n--------------------\n\n"),
298
+ ].join("\n");
299
+ }
300
+ function renderLevels(entry) {
301
+ if (!entry) {
302
+ return [];
303
+ }
304
+ const levelRows = [
305
+ ["当前价格", entry.current_price],
306
+ ["止损位", entry.stop_loss],
307
+ ["突破位", entry.breakthrough],
308
+ ["支撑位", entry.support],
309
+ ["成本位", entry.cost_level],
310
+ ["压力位", entry.resistance],
311
+ ["止盈位", entry.take_profit],
312
+ ["缺口位", entry.gap],
313
+ ["目标位", entry.target],
314
+ ["整数关", entry.round_number],
315
+ ];
316
+ return levelRows
317
+ .filter(([, value]) => value != null)
318
+ .map(([label, value]) => `${label}: ${formatPrice(value)}`);
319
+ }
320
+ function renderStringSection(title, items) {
321
+ if (items.length === 0) {
322
+ return [];
323
+ }
324
+ return [`${title}:`, ...items.map((item, index) => `${index + 1}. ${item}`)];
325
+ }
326
+ function renderScoreLine(label, score) {
327
+ return `${label}: ${score == null ? "暂无" : `${score}/10`}`;
328
+ }
329
+ function renderBias(bias) {
330
+ if (bias === "positive") {
331
+ return "偏多";
332
+ }
333
+ if (bias === "negative") {
334
+ return "偏空";
335
+ }
336
+ return "中性";
337
+ }
338
+ function formatPrice(value) {
339
+ if (!Number.isFinite(Number(value))) {
340
+ return "-";
341
+ }
342
+ return Number(value).toFixed(2);
343
+ }
@@ -0,0 +1,23 @@
1
+ import { MxApiService } from "./mx-search-service.js";
2
+ export interface FinancialLiteMetric {
3
+ id: string;
4
+ label: string;
5
+ value: number | string | null;
6
+ unit: string | null;
7
+ asOf: string | null;
8
+ }
9
+ export interface FinancialLiteSnapshot {
10
+ symbol: string;
11
+ companyName: string;
12
+ query: string;
13
+ asOf: string | null;
14
+ parserText: string | null;
15
+ rowName: string | null;
16
+ metrics: FinancialLiteMetric[];
17
+ }
18
+ export declare class FinancialLiteService {
19
+ private readonly mxApiService;
20
+ constructor(mxApiService: MxApiService);
21
+ isConfigured(): boolean;
22
+ fetchSnapshot(symbol: string, companyName: string): Promise<FinancialLiteSnapshot | null>;
23
+ }
@@ -0,0 +1,201 @@
1
+ const MAX_METRICS = 12;
2
+ const METRIC_MATCHERS = [
3
+ { id: "roe", label: "ROE", patterns: [/(\b|_)roe(\b|_)/i, /净资产收益率/] },
4
+ { id: "roa", label: "ROA", patterns: [/(\b|_)roa(\b|_)/i, /总资产收益率/] },
5
+ { id: "gross_margin", label: "毛利率", patterns: [/gross[\s_-]*margin/i, /毛利率/] },
6
+ { id: "net_margin", label: "净利率", patterns: [/net[\s_-]*margin/i, /净利率/] },
7
+ {
8
+ id: "revenue_yoy",
9
+ label: "营收同比",
10
+ patterns: [/revenue[\s_-]*yoy/i, /营收同比/, /营业收入同比/],
11
+ },
12
+ {
13
+ id: "net_income_yoy",
14
+ label: "净利润同比",
15
+ patterns: [/net[\s_-]*income[\s_-]*yoy/i, /净利润同比/, /归母净利润同比/],
16
+ },
17
+ {
18
+ id: "debt_to_asset_ratio",
19
+ label: "资产负债率",
20
+ patterns: [/debt[\s_-]*to[\s_-]*asset/i, /资产负债率/],
21
+ },
22
+ {
23
+ id: "ocfps",
24
+ label: "每股经营现金流",
25
+ patterns: [/ocfps/i, /每股经营现金流/, /每股经营现金流量/],
26
+ },
27
+ {
28
+ id: "operating_cash_to_revenue",
29
+ label: "销售现金比率",
30
+ patterns: [/operating[\s_-]*cash[\s_-]*to[\s_-]*revenue/i, /销售现金比率/],
31
+ },
32
+ { id: "eps", label: "每股收益", patterns: [/(\b|_)(eps|basic_eps|eps_basic)(\b|_)/i, /每股收益/] },
33
+ { id: "bps", label: "每股净资产", patterns: [/(\b|_)bps(\b|_)/i, /每股净资产/] },
34
+ ];
35
+ const CODE_PATTERNS = [/security[\s_-]*code/i, /secu[\s_-]*code/i, /股票代码/, /证券代码/, /^代码$/];
36
+ const NAME_PATTERNS = [
37
+ /security[\s_-]*short[\s_-]*name/i,
38
+ /security[\s_-]*name/i,
39
+ /secu[\s_-]*name/i,
40
+ /股票简称/,
41
+ /证券简称/,
42
+ /^名称$/,
43
+ ];
44
+ export class FinancialLiteService {
45
+ mxApiService;
46
+ constructor(mxApiService) {
47
+ this.mxApiService = mxApiService;
48
+ }
49
+ isConfigured() {
50
+ return this.mxApiService.isConfigured();
51
+ }
52
+ async fetchSnapshot(symbol, companyName) {
53
+ if (!this.isConfigured()) {
54
+ return null;
55
+ }
56
+ const query = buildFinancialLiteQuery(symbol, companyName);
57
+ const result = await this.mxApiService.selectStocks({
58
+ keyword: query,
59
+ pageNo: 1,
60
+ pageSize: 20,
61
+ });
62
+ const row = selectTargetRow(result, symbol, companyName);
63
+ if (!row) {
64
+ return null;
65
+ }
66
+ const metrics = selectFinancialMetrics(result.columns, row);
67
+ if (metrics.length === 0) {
68
+ return null;
69
+ }
70
+ return {
71
+ symbol,
72
+ companyName,
73
+ query,
74
+ asOf: resolveSnapshotAsOf(metrics),
75
+ parserText: result.parserText,
76
+ rowName: resolveRowName(result.columns, row),
77
+ metrics,
78
+ };
79
+ }
80
+ }
81
+ function buildFinancialLiteQuery(symbol, companyName) {
82
+ const securityName = companyName && companyName !== symbol ? `${companyName} ${symbol}` : symbol;
83
+ return `${securityName} 财务指标 ROE ROA 毛利率 净利率 营收同比 净利润同比 资产负债率 每股经营现金流 每股收益 每股净资产`;
84
+ }
85
+ function selectTargetRow(result, symbol, companyName) {
86
+ if (result.dataList.length === 0) {
87
+ return null;
88
+ }
89
+ const codeColumn = findIdentityColumn(result.columns, CODE_PATTERNS);
90
+ const nameColumn = findIdentityColumn(result.columns, NAME_PATTERNS);
91
+ const normalizedSymbol = normalizePlainText(symbol).replace(/\.(sz|sh|hk|us)$/i, "");
92
+ const normalizedName = normalizePlainText(companyName);
93
+ let bestRow = null;
94
+ let bestScore = -1;
95
+ for (const row of result.dataList) {
96
+ const codeValue = codeColumn ? normalizePlainText(row[codeColumn.key]).replace(/\.(sz|sh|hk|us)$/i, "") : "";
97
+ const nameValue = nameColumn ? normalizePlainText(row[nameColumn.key]) : "";
98
+ let score = 0;
99
+ if (codeValue && (codeValue === normalizedSymbol || normalizedSymbol.endsWith(codeValue))) {
100
+ score += 3;
101
+ }
102
+ if (normalizedName && nameValue && normalizedName.includes(nameValue)) {
103
+ score += 2;
104
+ }
105
+ if (score > bestScore) {
106
+ bestScore = score;
107
+ bestRow = row;
108
+ }
109
+ }
110
+ return bestRow ?? result.dataList[0] ?? null;
111
+ }
112
+ function findIdentityColumn(columns, patterns) {
113
+ return (columns.find((column) => {
114
+ const normalized = normalizeColumnToken(column.title, column.key);
115
+ return patterns.some((pattern) => pattern.test(normalized));
116
+ }) ?? null);
117
+ }
118
+ function selectFinancialMetrics(columns, row) {
119
+ const metrics = [];
120
+ const usedIds = new Set();
121
+ for (const column of columns) {
122
+ const matcher = matchMetricColumn(column);
123
+ if (!matcher || usedIds.has(matcher.id)) {
124
+ continue;
125
+ }
126
+ const value = normalizeMetricValue(row[column.key]);
127
+ if (value == null || value === "") {
128
+ continue;
129
+ }
130
+ usedIds.add(matcher.id);
131
+ metrics.push({
132
+ id: matcher.id,
133
+ label: matcher.label,
134
+ value,
135
+ unit: column.unit,
136
+ asOf: column.dateMsg,
137
+ });
138
+ if (metrics.length >= MAX_METRICS) {
139
+ break;
140
+ }
141
+ }
142
+ return metrics;
143
+ }
144
+ function matchMetricColumn(column) {
145
+ const normalized = normalizeColumnToken(column.title, column.key);
146
+ for (const matcher of METRIC_MATCHERS) {
147
+ if (matcher.patterns.some((pattern) => pattern.test(normalized))) {
148
+ return {
149
+ id: matcher.id,
150
+ label: matcher.label,
151
+ };
152
+ }
153
+ }
154
+ return null;
155
+ }
156
+ function resolveSnapshotAsOf(metrics) {
157
+ const values = metrics
158
+ .map((metric) => metric.asOf?.trim() ?? "")
159
+ .filter(Boolean);
160
+ if (values.length === 0) {
161
+ return null;
162
+ }
163
+ const counts = new Map();
164
+ for (const value of values) {
165
+ counts.set(value, (counts.get(value) ?? 0) + 1);
166
+ }
167
+ return [...counts.entries()].sort((left, right) => right[1] - left[1])[0]?.[0] ?? values[0];
168
+ }
169
+ function resolveRowName(columns, row) {
170
+ const nameColumn = findIdentityColumn(columns, NAME_PATTERNS);
171
+ if (!nameColumn) {
172
+ return null;
173
+ }
174
+ const value = row[nameColumn.key];
175
+ return typeof value === "string" && value.trim() ? value.trim() : null;
176
+ }
177
+ function normalizeMetricValue(value) {
178
+ if (value == null) {
179
+ return null;
180
+ }
181
+ if (typeof value === "number") {
182
+ return Number.isFinite(value) ? value : null;
183
+ }
184
+ const text = String(value).trim();
185
+ if (!text || text === "--" || text === "-") {
186
+ return null;
187
+ }
188
+ if (/^-?\d+(\.\d+)?$/.test(text)) {
189
+ const numeric = Number(text);
190
+ return Number.isFinite(numeric) ? numeric : text;
191
+ }
192
+ return text;
193
+ }
194
+ function normalizeColumnToken(title, key) {
195
+ return `${title} ${key}`.replace(/\s+/g, " ").trim();
196
+ }
197
+ function normalizePlainText(value) {
198
+ return String(value ?? "")
199
+ .trim()
200
+ .toLowerCase();
201
+ }
@@ -0,0 +1,20 @@
1
+ import type { TickFlowBalanceSheetRecord, TickFlowCashFlowRecord, TickFlowFinancialMetricsRecord, TickFlowFinancialQueryOptions, TickFlowIncomeRecord } from "../types/tickflow.js";
2
+ import { TickFlowClient } from "./tickflow-client.js";
3
+ export type FinancialSection = "income" | "metrics" | "cash_flow" | "balance_sheet";
4
+ export declare const ALL_FINANCIAL_SECTIONS: FinancialSection[];
5
+ export interface FinancialSnapshot {
6
+ symbol: string;
7
+ income: TickFlowIncomeRecord[];
8
+ metrics: TickFlowFinancialMetricsRecord[];
9
+ cashFlow: TickFlowCashFlowRecord[];
10
+ balanceSheet: TickFlowBalanceSheetRecord[];
11
+ }
12
+ export declare class FinancialService {
13
+ private readonly client;
14
+ constructor(client: TickFlowClient);
15
+ fetchIncome(symbol: string, options?: TickFlowFinancialQueryOptions): Promise<TickFlowIncomeRecord[]>;
16
+ fetchMetrics(symbol: string, options?: TickFlowFinancialQueryOptions): Promise<TickFlowFinancialMetricsRecord[]>;
17
+ fetchCashFlow(symbol: string, options?: TickFlowFinancialQueryOptions): Promise<TickFlowCashFlowRecord[]>;
18
+ fetchBalanceSheet(symbol: string, options?: TickFlowFinancialQueryOptions): Promise<TickFlowBalanceSheetRecord[]>;
19
+ fetchSnapshot(symbol: string, options?: TickFlowFinancialQueryOptions, sections?: FinancialSection[]): Promise<FinancialSnapshot>;
20
+ }