1use crate::handlers;
4use crate::tool_args::*;
5use rmcp::{
6 RoleServer, handler::server::wrapper::Parameters, service::RequestContext, tool, tool_router,
7};
8
9use super::FutuServer;
10
11#[tool_router(router = reference_f10_tool_router, vis = "pub(crate)")]
12impl FutuServer {
13 #[tool(
14 description = "Company operational efficiency metrics such as employees and per-capita income/profit. Futu API v10.6: OpenQuoteContext.get_company_operational_efficiency."
15 )]
16 async fn futu_get_company_operational_efficiency(
17 &self,
18 Parameters(req): Parameters<CompanyOperationalEfficiencyReq>,
19 req_ctx: RequestContext<RoleServer>,
20 ) -> std::result::Result<String, String> {
21 req.validate()?;
22 tracing::info!(
23 tool = "futu_get_company_operational_efficiency",
24 symbol = %req.symbol,
25 next_key = %crate::state::audit_fmt::opt_str(req.next_key.as_deref()),
26 num = ?req.num,
27 currency_code = %crate::state::audit_fmt::opt_str(req.currency_code.as_deref()),
28 financial_type = ?req.financial_type
29 );
30 let client = self
31 .read_client_or_err(
32 "futu_get_company_operational_efficiency",
33 &req_ctx,
34 None,
35 None,
36 )
37 .await?;
38 Self::wrap_result(
39 handlers::reference::get_company_operational_efficiency(
40 &client,
41 &req.symbol,
42 req.next_key.as_deref(),
43 req.num,
44 req.currency_code.as_deref(),
45 req.financial_type,
46 )
47 .await,
48 )
49 }
50
51 #[tool(
52 description = "Price move around financial earnings announcement dates. Futu API v10.6: OpenQuoteContext.get_financials_earnings_price_move."
53 )]
54 async fn futu_get_financials_earnings_price_move(
55 &self,
56 Parameters(req): Parameters<FinancialsEarningsPriceMoveReq>,
57 req_ctx: RequestContext<RoleServer>,
58 ) -> std::result::Result<String, String> {
59 req.validate()?;
60 tracing::info!(
61 tool = "futu_get_financials_earnings_price_move",
62 symbol = %req.symbol,
63 period_count = ?req.period_count
64 );
65 let client = self
66 .read_client_or_err(
67 "futu_get_financials_earnings_price_move",
68 &req_ctx,
69 None,
70 None,
71 )
72 .await?;
73 Self::wrap_result(
74 handlers::reference::get_financials_earnings_price_move(
75 &client,
76 &req.symbol,
77 req.period_count,
78 )
79 .await,
80 )
81 }
82
83 #[tool(
84 description = "Price history around financial earnings announcement dates. Futu API v10.6: OpenQuoteContext.get_financials_earnings_price_history."
85 )]
86 async fn futu_get_financials_earnings_price_history(
87 &self,
88 Parameters(req): Parameters<FinancialsEarningsPriceHistoryReq>,
89 req_ctx: RequestContext<RoleServer>,
90 ) -> std::result::Result<String, String> {
91 tracing::info!(
92 tool = "futu_get_financials_earnings_price_history",
93 symbol = %req.symbol
94 );
95 let client = self
96 .read_client_or_err(
97 "futu_get_financials_earnings_price_history",
98 &req_ctx,
99 None,
100 None,
101 )
102 .await?;
103 Self::wrap_result(
104 handlers::reference::get_financials_earnings_price_history(&client, &req.symbol).await,
105 )
106 }
107
108 #[tool(
109 description = "Read-only financial calendar view. Rust enhancement backed by the mobile calendar service; not a C++ FTAPI parity endpoint."
110 )]
111 async fn futu_get_financial_calendar(
112 &self,
113 Parameters(req): Parameters<FinancialCalendarReq>,
114 req_ctx: RequestContext<RoleServer>,
115 ) -> std::result::Result<String, String> {
116 req.validate()?;
117 tracing::info!(
118 tool = "futu_get_financial_calendar",
119 begin_date = %req.begin_date,
120 end_date = %req.end_date,
121 markets = ?req.market_list,
122 count = ?req.count,
123 watchlist_stock_ids = req.watchlist_stock_ids.len(),
124 holding_stock_ids = req.holding_stock_ids.len()
125 );
126 let client = self
127 .read_client_or_err("futu_get_financial_calendar", &req_ctx, None, None)
128 .await?;
129 Self::wrap_result(
130 handlers::reference::get_financial_calendar(&client, req.to_proto()).await,
131 )
132 }
133
134 #[tool(
135 description = "Target-stock financial calendar search. Rust enhancement backed by the mobile calendar service; not a C++ FTAPI parity endpoint."
136 )]
137 async fn futu_search_target_financial_calendar(
138 &self,
139 Parameters(req): Parameters<TargetFinancialCalendarReq>,
140 req_ctx: RequestContext<RoleServer>,
141 ) -> std::result::Result<String, String> {
142 req.validate()?;
143 tracing::info!(
144 tool = "futu_search_target_financial_calendar",
145 stock_ids = req.stock_id.len(),
146 markets = ?req.market_list,
147 size = req.size,
148 start = ?req.start
149 );
150 let client = self
151 .read_client_or_err(
152 "futu_search_target_financial_calendar",
153 &req_ctx,
154 None,
155 None,
156 )
157 .await?;
158 Self::wrap_result(
159 handlers::reference::search_target_financial_calendar(&client, req.to_proto()).await,
160 )
161 }
162
163 #[tool(
164 description = "Financial statements. Futu API v10.6: OpenQuoteContext.get_financials_statements."
165 )]
166 async fn futu_get_financials_statements(
167 &self,
168 Parameters(req): Parameters<FinancialsStatementsReq>,
169 req_ctx: RequestContext<RoleServer>,
170 ) -> std::result::Result<String, String> {
171 req.validate()?;
172 tracing::info!(
173 tool = "futu_get_financials_statements",
174 symbol = %req.symbol,
175 statement_type = ?req.statement_type,
176 financial_type = ?req.financial_type,
177 currency_code = ?req.currency_code,
178 next_key = ?req.next_key,
179 num = ?req.num
180 );
181 let client = self
182 .read_client_or_err("futu_get_financials_statements", &req_ctx, None, None)
183 .await?;
184 Self::wrap_result(
185 handlers::reference::get_financials_statements(
186 &client,
187 &req.symbol,
188 req.statement_type,
189 req.financial_type,
190 req.currency_code.as_deref(),
191 req.next_key.as_deref(),
192 req.num,
193 )
194 .await,
195 )
196 }
197
198 #[tool(
199 description = "Financials revenue breakdown. Futu API v10.6: OpenQuoteContext.get_financials_revenue_breakdown."
200 )]
201 async fn futu_get_financials_revenue_breakdown(
202 &self,
203 Parameters(req): Parameters<FinancialsRevenueBreakdownReq>,
204 req_ctx: RequestContext<RoleServer>,
205 ) -> std::result::Result<String, String> {
206 req.validate()?;
207 tracing::info!(
208 tool = "futu_get_financials_revenue_breakdown",
209 symbol = %req.symbol,
210 date = ?req.date,
211 financial_type = ?req.financial_type,
212 currency_code = ?req.currency_code
213 );
214 let client = self
215 .read_client_or_err(
216 "futu_get_financials_revenue_breakdown",
217 &req_ctx,
218 None,
219 None,
220 )
221 .await?;
222 Self::wrap_result(
223 handlers::reference::get_financials_revenue_breakdown(
224 &client,
225 &req.symbol,
226 req.date,
227 req.financial_type,
228 req.currency_code.as_deref(),
229 )
230 .await,
231 )
232 }
233
234 #[tool(
235 description = "Research analyst consensus. Futu API v10.6: OpenQuoteContext.get_research_analyst_consensus."
236 )]
237 async fn futu_get_research_analyst_consensus(
238 &self,
239 Parameters(req): Parameters<ResearchAnalystConsensusReq>,
240 req_ctx: RequestContext<RoleServer>,
241 ) -> std::result::Result<String, String> {
242 tracing::info!(
243 tool = "futu_get_research_analyst_consensus",
244 symbol = %req.symbol
245 );
246 let client = self
247 .read_client_or_err("futu_get_research_analyst_consensus", &req_ctx, None, None)
248 .await?;
249 Self::wrap_result(
250 handlers::reference::get_research_analyst_consensus(&client, &req.symbol).await,
251 )
252 }
253
254 #[tool(
255 description = "Research rating summary/detail list. Futu API v10.6: OpenQuoteContext.get_research_rating_summary."
256 )]
257 async fn futu_get_research_rating_summary(
258 &self,
259 Parameters(req): Parameters<ResearchRatingSummaryReq>,
260 req_ctx: RequestContext<RoleServer>,
261 ) -> std::result::Result<String, String> {
262 req.validate()?;
263 tracing::info!(
264 tool = "futu_get_research_rating_summary",
265 symbol = %req.symbol,
266 rating_dimension_type = ?req.rating_dimension_type,
267 uid = ?req.uid,
268 next_key = ?req.next_key,
269 num = ?req.num
270 );
271 let client = self
272 .read_client_or_err("futu_get_research_rating_summary", &req_ctx, None, None)
273 .await?;
274 Self::wrap_result(
275 handlers::reference::get_research_rating_summary(
276 &client,
277 &req.symbol,
278 req.rating_dimension_type,
279 req.uid.as_deref(),
280 req.next_key.as_deref(),
281 req.num,
282 )
283 .await,
284 )
285 }
286
287 #[tool(
288 description = "Morningstar research report. Futu API v10.6: OpenQuoteContext.get_research_morningstar_report."
289 )]
290 async fn futu_get_research_morningstar_report(
291 &self,
292 Parameters(req): Parameters<ResearchMorningstarReportReq>,
293 req_ctx: RequestContext<RoleServer>,
294 ) -> std::result::Result<String, String> {
295 tracing::info!(
296 tool = "futu_get_research_morningstar_report",
297 symbol = %req.symbol
298 );
299 let client = self
300 .read_client_or_err("futu_get_research_morningstar_report", &req_ctx, None, None)
301 .await?;
302 Self::wrap_result(
303 handlers::reference::get_research_morningstar_report(&client, &req.symbol).await,
304 )
305 }
306
307 #[tool(
308 description = "Valuation detail for a stock or index. Futu API v10.6: OpenQuoteContext.get_valuation_detail."
309 )]
310 async fn futu_get_valuation_detail(
311 &self,
312 Parameters(req): Parameters<ValuationDetailReq>,
313 req_ctx: RequestContext<RoleServer>,
314 ) -> std::result::Result<String, String> {
315 req.validate()?;
316 tracing::info!(
317 tool = "futu_get_valuation_detail",
318 symbol = %req.symbol,
319 valuation_type = ?req.valuation_type,
320 interval_type = ?req.interval_type
321 );
322 let client = self
323 .read_client_or_err("futu_get_valuation_detail", &req_ctx, None, None)
324 .await?;
325 Self::wrap_result(
326 handlers::reference::get_valuation_detail(
327 &client,
328 &req.symbol,
329 req.valuation_type,
330 req.interval_type,
331 )
332 .await,
333 )
334 }
335
336 #[tool(
337 description = "Valuation stock list for a plate or index. Futu API v10.6: OpenQuoteContext.get_valuation_plate_stock_list."
338 )]
339 async fn futu_get_valuation_plate_stock_list(
340 &self,
341 Parameters(req): Parameters<ValuationPlateStockListReq>,
342 req_ctx: RequestContext<RoleServer>,
343 ) -> std::result::Result<String, String> {
344 req.validate()?;
345 tracing::info!(
346 tool = "futu_get_valuation_plate_stock_list",
347 symbol = %req.symbol,
348 valuation_type = ?req.valuation_type,
349 next_key = ?req.next_key,
350 num = ?req.num,
351 sort_type = ?req.sort_type,
352 sort_id = ?req.sort_id,
353 filter_security = ?req.filter_security
354 );
355 let client = self
356 .read_client_or_err("futu_get_valuation_plate_stock_list", &req_ctx, None, None)
357 .await?;
358 Self::wrap_result(
359 handlers::reference::get_valuation_plate_stock_list(
360 &client,
361 &req.symbol,
362 req.valuation_type,
363 req.next_key.as_deref(),
364 req.num,
365 req.sort_type,
366 req.sort_id,
367 req.filter_security.as_deref(),
368 )
369 .await,
370 )
371 }
372}