longbridge/grid/
context.rs1use std::sync::Arc;
2
3use longbridge_httpcli::{HttpClient, Json, Method};
4use serde::{Deserialize, Serialize};
5use tracing::{Subscriber, dispatcher, instrument::WithSubscriber};
6
7use crate::{
8 Config, Result,
9 grid::{
10 GetGridOrderDetailOptions, GetGridOrdersByIdsOptions, GetGridOrdersOptions,
11 GetGridTriggerHistoryOptions, GridOrder, GridOrderDetail, GridSymbolInfo,
12 ReplaceGridOrderOptions, SubmitGridOrderOptions, TriggerOrder,
13 },
14};
15
16#[derive(Debug, Deserialize)]
17struct EmptyResponse {}
18
19#[derive(Debug, Serialize, Deserialize)]
21pub struct SubmitGridOrderResponse {
22 pub order_id: String,
24}
25
26#[derive(Debug, Deserialize)]
28pub struct GridOrdersResponse {
29 #[serde(default)]
31 pub grid_order: Vec<GridOrder>,
32 #[serde(default)]
34 pub has_more: bool,
35}
36
37#[derive(Debug, Deserialize)]
39pub struct GridTriggerHistoryResponse {
40 #[serde(default)]
42 pub trigger_orders: Vec<TriggerOrder>,
43 #[serde(default)]
45 pub has_more: bool,
46}
47
48struct InnerGridContext {
49 http_cli: HttpClient,
50 log_subscriber: Arc<dyn Subscriber + Send + Sync>,
51}
52
53impl Drop for InnerGridContext {
54 fn drop(&mut self) {
55 dispatcher::with_default(&self.log_subscriber.clone().into(), || {
56 tracing::info!("grid context dropped");
57 });
58 }
59}
60
61#[derive(Clone)]
63pub struct GridContext(Arc<InnerGridContext>);
64
65impl GridContext {
66 pub fn new(config: Arc<Config>) -> Self {
68 let log_subscriber = config.create_log_subscriber("grid");
69 dispatcher::with_default(&log_subscriber.clone().into(), || {
70 tracing::info!(language = ?config.language, "creating grid context");
71 });
72 let ctx = Self(Arc::new(InnerGridContext {
73 http_cli: config.create_http_client(),
74 log_subscriber,
75 }));
76 dispatcher::with_default(&ctx.0.log_subscriber.clone().into(), || {
77 tracing::info!("grid context created");
78 });
79 ctx
80 }
81
82 #[inline]
84 pub fn log_subscriber(&self) -> Arc<dyn Subscriber + Send + Sync> {
85 self.0.log_subscriber.clone()
86 }
87
88 pub async fn submit(&self, options: SubmitGridOrderOptions) -> Result<SubmitGridOrderResponse> {
90 Ok(self
91 .0
92 .http_cli
93 .request(Method::POST, "/v1/gridtrading/submit")
94 .body(Json(options))
95 .response::<Json<SubmitGridOrderResponse>>()
96 .send()
97 .with_subscriber(self.0.log_subscriber.clone())
98 .await?
99 .0)
100 }
101
102 pub async fn replace(&self, options: ReplaceGridOrderOptions) -> Result<()> {
104 self.0
105 .http_cli
106 .request(Method::POST, "/v1/gridtrading/replace")
107 .body(Json(options))
108 .response::<Json<EmptyResponse>>()
109 .send()
110 .with_subscriber(self.0.log_subscriber.clone())
111 .await?;
112 Ok(())
113 }
114
115 pub async fn list(
117 &self,
118 options: impl Into<Option<GetGridOrdersOptions>>,
119 ) -> Result<GridOrdersResponse> {
120 Ok(self
121 .0
122 .http_cli
123 .request(Method::GET, "/v1/gridtrading/list")
124 .query_params(options.into().unwrap_or_default())
125 .response::<Json<GridOrdersResponse>>()
126 .send()
127 .with_subscriber(self.0.log_subscriber.clone())
128 .await?
129 .0)
130 }
131
132 pub async fn list_by_ids(&self, options: GetGridOrdersByIdsOptions) -> Result<Vec<GridOrder>> {
134 #[derive(Deserialize)]
135 struct Response {
136 #[serde(default)]
137 grid_order: Vec<GridOrder>,
138 }
139
140 Ok(self
141 .0
142 .http_cli
143 .request(Method::POST, "/v1/gridtrading/list")
144 .body(Json(options))
145 .response::<Json<Response>>()
146 .send()
147 .with_subscriber(self.0.log_subscriber.clone())
148 .await?
149 .0
150 .grid_order)
151 }
152
153 pub async fn detail(&self, options: GetGridOrderDetailOptions) -> Result<GridOrderDetail> {
155 Ok(self
156 .0
157 .http_cli
158 .request(Method::GET, "/v1/gridtrading/detail")
159 .query_params(options)
160 .response::<Json<GridOrderDetail>>()
161 .send()
162 .with_subscriber(self.0.log_subscriber.clone())
163 .await?
164 .0)
165 }
166
167 pub async fn trigger_history(
169 &self,
170 options: GetGridTriggerHistoryOptions,
171 ) -> Result<GridTriggerHistoryResponse> {
172 Ok(self
173 .0
174 .http_cli
175 .request(Method::GET, "/v1/gridtrading/trigger_history_list")
176 .query_params(options)
177 .response::<Json<GridTriggerHistoryResponse>>()
178 .send()
179 .with_subscriber(self.0.log_subscriber.clone())
180 .await?
181 .0)
182 }
183
184 pub async fn cancel(&self, order_id: impl Into<String>) -> Result<()> {
186 self.grid_action("/v1/gridtrading/cancel", order_id).await
187 }
188
189 pub async fn suspend(&self, order_id: impl Into<String>) -> Result<()> {
191 self.grid_action("/v1/gridtrading/suspend", order_id).await
192 }
193
194 pub async fn restart(&self, order_id: impl Into<String>) -> Result<()> {
196 self.grid_action("/v1/gridtrading/restart", order_id).await
197 }
198
199 async fn grid_action(&self, path: &'static str, order_id: impl Into<String>) -> Result<()> {
201 #[derive(Debug, Serialize)]
202 struct Body {
203 order_id: String,
204 }
205
206 self.0
207 .http_cli
208 .request(Method::POST, path)
209 .body(Json(Body {
210 order_id: order_id.into(),
211 }))
212 .response::<Json<EmptyResponse>>()
213 .send()
214 .with_subscriber(self.0.log_subscriber.clone())
215 .await?;
216 Ok(())
217 }
218
219 pub async fn symbol_info(&self, symbol: impl Into<String>) -> Result<GridSymbolInfo> {
222 #[derive(Debug, Serialize)]
223 struct Query {
224 symbol: String,
225 }
226
227 Ok(self
228 .0
229 .http_cli
230 .request(Method::GET, "/v1/orders/info")
231 .query_params(Query {
232 symbol: symbol.into(),
233 })
234 .response::<Json<GridSymbolInfo>>()
235 .send()
236 .with_subscriber(self.0.log_subscriber.clone())
237 .await?
238 .0)
239 }
240}