futu_mcp/handlers/core/
ping_quote.rs1use std::sync::Arc;
5use std::time::Duration;
6
7use anyhow::Result;
8use futu_net::client::FutuClient;
9use futu_qot::types::SubType;
10use serde::Serialize;
11
12use crate::state::{format_symbol, parse_symbol};
13
14#[derive(Serialize)]
15pub struct PingOut {
16 pub gateway: String,
17 pub ok: bool,
18 pub rtt_ms: f64,
19 pub message: String,
20}
21
22pub async fn ping(client: &Arc<FutuClient>, gateway: &str) -> PingOut {
23 let t0 = std::time::Instant::now();
24 match futu_qot::market_misc::get_sub_info(client, false).await {
25 Ok(_) => PingOut {
26 gateway: gateway.to_string(),
27 ok: true,
28 rtt_ms: t0.elapsed().as_secs_f64() * 1000.0,
29 message: "pong".into(),
30 },
31 Err(e) => PingOut {
32 gateway: gateway.to_string(),
33 ok: false,
34 rtt_ms: 0.0,
35 message: format!("request failed: {e}"),
36 },
37 }
38}
39
40#[derive(Serialize)]
41struct QuoteOut {
42 symbol: String,
43 update_time: String,
44 cur_price: f64,
45 last_close: f64,
46 open: f64,
47 high: f64,
48 low: f64,
49 volume: i64,
50 turnover: f64,
51 turnover_rate: f64,
52 amplitude: f64,
53 change_rate: f64,
54}
55
56pub async fn get_quote(client: &Arc<FutuClient>, symbol: &str) -> Result<String> {
57 let sec = parse_symbol(symbol)?;
58
59 futu_qot::sub::subscribe(
60 client,
61 std::slice::from_ref(&sec),
62 &[SubType::Basic],
63 true,
64 true,
65 )
66 .await?;
67 tokio::time::sleep(Duration::from_millis(300)).await;
68
69 let qots = futu_qot::basic_qot::get_basic_qot(client, std::slice::from_ref(&sec)).await?;
70 let q = qots
71 .first()
72 .ok_or_else(|| anyhow::anyhow!("empty quote result"))?;
73
74 let change_rate = if q.last_close_price.abs() > f64::EPSILON {
75 (q.cur_price - q.last_close_price) / q.last_close_price * 100.0
76 } else {
77 0.0
78 };
79
80 let out = QuoteOut {
81 symbol: format_symbol(&q.security),
82 update_time: q.update_time.clone(),
83 cur_price: q.cur_price,
84 last_close: q.last_close_price,
85 open: q.open_price,
86 high: q.high_price,
87 low: q.low_price,
88 volume: q.volume,
89 turnover: q.turnover,
90 turnover_rate: q.turnover_rate,
91 amplitude: q.amplitude,
92 change_rate,
93 };
94 Ok(serde_json::to_string_pretty(&out)?)
95}