|
|
@@ -3,6 +3,7 @@ use std::sync::Arc;
|
|
|
use anyhow::{anyhow, bail, Result};
|
|
|
use rust_decimal::Decimal;
|
|
|
use std::time::{Duration, Instant};
|
|
|
+use serde_json::Value;
|
|
|
use tokio::sync::Mutex;
|
|
|
use tokio::time::sleep;
|
|
|
use tracing::{info, warn};
|
|
|
@@ -156,14 +157,15 @@ impl Strategy {
|
|
|
self.last_query_order_time = Instant::now();
|
|
|
|
|
|
// 检查订单是否已成交
|
|
|
- match self.check_order_filled(&order_id, dm).await {
|
|
|
- Ok(true) => {
|
|
|
- info!("限价单已成交,准备执行市价单");
|
|
|
- self.state = StrategyState::ExecutingMarketOrder { };
|
|
|
- return Ok(());
|
|
|
- }
|
|
|
- Ok(false) => {
|
|
|
- // 订单未成交,继续检查价格
|
|
|
+ match self.check_order_filled_status(&order_id, dm).await {
|
|
|
+ Ok(status) => {
|
|
|
+ let has_filled = matches!(status.as_str(), "FILLED");
|
|
|
+
|
|
|
+ if has_filled {
|
|
|
+ info!("限价单已成交,准备执行市价单");
|
|
|
+ self.state = StrategyState::ExecutingMarketOrder { };
|
|
|
+ return Ok(());
|
|
|
+ }
|
|
|
}
|
|
|
Err(e) => {
|
|
|
return Err(e);
|
|
|
@@ -198,18 +200,21 @@ impl Strategy {
|
|
|
sleep(Duration::from_millis(3000)).await;
|
|
|
|
|
|
// 撤单后检查是否有成交
|
|
|
- match self.check_order_partially_filled(&order_id, dm).await {
|
|
|
- Ok(true) => {
|
|
|
- info!("撤单后发现有成交,准备执行市价单");
|
|
|
- self.state = StrategyState::ExecutingMarketOrder { };
|
|
|
- Ok(())
|
|
|
- }
|
|
|
- Ok(false) => {
|
|
|
- info!("撤单完成,无成交,返回空闲状态");
|
|
|
- self.state = StrategyState::Idle;
|
|
|
+ match self.check_order_filled_status(&order_id, dm).await {
|
|
|
+ Ok(status) => {
|
|
|
+ let has_filled = matches!(status.as_str(), "PARTIALLY_FILLED" | "FILLED");
|
|
|
+
|
|
|
+ if has_filled {
|
|
|
+ info!("撤单后发现有成交,准备执行市价单");
|
|
|
+ self.state = StrategyState::ExecutingMarketOrder { };
|
|
|
+ } else {
|
|
|
+ info!("撤单完成,无成交,返回空闲状态");
|
|
|
+ self.state = StrategyState::Idle;
|
|
|
+ }
|
|
|
Ok(())
|
|
|
}
|
|
|
Err(e) => {
|
|
|
+ warn!("检查订单成交状态失败: {}", e);
|
|
|
Err(e)
|
|
|
}
|
|
|
}
|
|
|
@@ -259,19 +264,29 @@ impl Strategy {
|
|
|
self.last_query_order_time = Instant::now();
|
|
|
|
|
|
// 等待市价单成交(市价单通常立即成交)
|
|
|
- match self.check_order_filled(&order_id, dm).await {
|
|
|
- Ok(true) => {
|
|
|
- info!("市价单已成交,返回空闲状态");
|
|
|
-
|
|
|
- self.state = StrategyState::Idle;
|
|
|
- self.filled_quantity = Decimal::ZERO;
|
|
|
-
|
|
|
- Ok(())
|
|
|
- }
|
|
|
- Ok(false) => {
|
|
|
- self.state = StrategyState::ExecutingMarketOrder { };
|
|
|
-
|
|
|
- Ok(())
|
|
|
+ match self.check_order_filled_status(&order_id, dm).await {
|
|
|
+ Ok(status) => {
|
|
|
+ match status.as_str() {
|
|
|
+ "PARTIALLY_FILLED" | "FILLED" => {
|
|
|
+ info!("市价单已成交,返回空闲状态");
|
|
|
+
|
|
|
+ self.state = StrategyState::Idle;
|
|
|
+ self.filled_quantity = Decimal::ZERO;
|
|
|
+
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+ "CANCELLED" => {
|
|
|
+ info!("市价单已被取消,重新下单");
|
|
|
+
|
|
|
+ self.state = StrategyState::ExecutingMarketOrder { };
|
|
|
+
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+ _ => {
|
|
|
+ // 这里是其他状态,等待市价单终止
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
Err(e) => {
|
|
|
Err(e)
|
|
|
@@ -293,6 +308,7 @@ impl Strategy {
|
|
|
"BUY",
|
|
|
quantity.to_string().as_str(),
|
|
|
price.to_string().as_str(),
|
|
|
+ true,
|
|
|
false,
|
|
|
).await;
|
|
|
|
|
|
@@ -311,6 +327,7 @@ impl Strategy {
|
|
|
"SELL",
|
|
|
quantity.to_string().as_str(),
|
|
|
price.to_string().as_str(),
|
|
|
+ false,
|
|
|
true,
|
|
|
).await;
|
|
|
|
|
|
@@ -343,23 +360,19 @@ impl Strategy {
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
- /// 检查订单是否完全成交
|
|
|
- async fn check_order_filled(&mut self, order_id: &str, dm: &DataManager) -> Result<bool> {
|
|
|
- self.check_order_filled_status(order_id, dm, true).await
|
|
|
- }
|
|
|
-
|
|
|
- /// 检查订单是否有部分成交
|
|
|
- async fn check_order_partially_filled(&mut self, order_id: &str, dm: &DataManager) -> Result<bool> {
|
|
|
- self.check_order_filled_status(order_id, dm, false).await
|
|
|
- }
|
|
|
-
|
|
|
/// 检查订单成交状态
|
|
|
/// - `require_full_fill`: true 表示只接受完全成交,false 表示部分成交也接受
|
|
|
- async fn check_order_filled_status(&mut self, order_id: &str, dm: &DataManager, require_full_fill: bool) -> Result<bool> {
|
|
|
- let check_type = if require_full_fill { "完全成交" } else { "部分成交" };
|
|
|
+ async fn check_order_filled_status(&mut self, order_id: &str, dm: &DataManager) -> Result<String> {
|
|
|
+ let data_option = dm.extended_orders.get(order_id);
|
|
|
|
|
|
- let data = dm.extended_orders.get(order_id)
|
|
|
- .ok_or_else(|| anyhow!("订单暂时不存在: {}", order_id))?;
|
|
|
+ let data = match data_option {
|
|
|
+ Some(data) => { data },
|
|
|
+ None => {
|
|
|
+ warn!("订单暂时不存在ws缓存中: {}, 使用rest方式获取。", order_id);
|
|
|
+
|
|
|
+ &self.get_order_result(order_id).await?
|
|
|
+ }
|
|
|
+ };
|
|
|
|
|
|
let data_str = serde_json::to_string(&data)
|
|
|
.unwrap_or_else(|_| "无法序列化 JSON Value".to_string());
|
|
|
@@ -369,28 +382,45 @@ impl Strategy {
|
|
|
.and_then(|v| v.as_str())
|
|
|
.ok_or_else(|| anyhow!("查单-获取 'data.status' 失败,原始JSON:{}", data_str))?;
|
|
|
|
|
|
- // 根据要求判断是否符合成交条件
|
|
|
- let is_filled = if require_full_fill {
|
|
|
- status == "FILLED"
|
|
|
- } else {
|
|
|
- status == "FILLED" || status == "PARTIALLY_FILLED"
|
|
|
- };
|
|
|
+ // 获取真实成交数量
|
|
|
+ let filled_qty = data.get("filledQty")
|
|
|
+ .and_then(|v| v.as_str())
|
|
|
+ .ok_or_else(|| anyhow!("查单-获取 'data.filledQty' 失败,原始JSON:{}", data_str))
|
|
|
+ .and_then(|v| Decimal::from_str(v)
|
|
|
+ .map_err(|e| anyhow!("查单-解析 'data.filledQty' 为 Decimal 失败: {}, 值: {}", e, v))
|
|
|
+ )?;
|
|
|
+
|
|
|
+ self.filled_quantity = filled_qty.normalize();
|
|
|
+ if self.filled_quantity > Decimal::ZERO {
|
|
|
+ info!("订单 {} ,成交数量: {}", order_id, self.filled_quantity);
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok(status.to_string())
|
|
|
+ }
|
|
|
+
|
|
|
+ async fn get_order_result(&self, order_id: &str) -> Result<Value> {
|
|
|
+ let mut client = self.rest_client.lock().await;
|
|
|
+ let response = client.get_order(order_id).await;
|
|
|
+
|
|
|
+ let value = &response.data;
|
|
|
|
|
|
- if is_filled {
|
|
|
- // 获取真实成交数量
|
|
|
- let filled_qty = data.get("filledQty")
|
|
|
- .and_then(|v| v.as_str())
|
|
|
- .ok_or_else(|| anyhow!("查单-获取 'data.filledQty' 失败,原始JSON:{}", data_str))
|
|
|
- .and_then(|v| Decimal::from_str(v)
|
|
|
- .map_err(|e| anyhow!("查单-解析 'data.filledQty' 为 Decimal 失败: {}, 值: {}", e, v))
|
|
|
- )?;
|
|
|
-
|
|
|
- self.filled_quantity = filled_qty.normalize();
|
|
|
- info!("订单 {} 已{},成交数量: {}", order_id, check_type, filled_qty);
|
|
|
- Ok(true)
|
|
|
- } else {
|
|
|
- Ok(false)
|
|
|
+ // 预先捕获整个 Value 的字符串表示,用于错误报告
|
|
|
+ let value_str = serde_json::to_string(&value)
|
|
|
+ .unwrap_or_else(|_| "无法序列化 JSON Value".to_string());
|
|
|
+
|
|
|
+ // 获取并判定 status
|
|
|
+ let status = value.get("status")
|
|
|
+ .and_then(|v| v.as_str())
|
|
|
+ .ok_or_else(|| anyhow!("查单-获取 'status' 失败,原始JSON:{}", value_str))?;
|
|
|
+
|
|
|
+ if status != "OK" {
|
|
|
+ bail!("查单失败,状态不为OK: {},原始JSON:{}", status, value_str)
|
|
|
}
|
|
|
+
|
|
|
+ // 获取 data 字段
|
|
|
+ value.get("data")
|
|
|
+ .cloned()
|
|
|
+ .ok_or_else(|| anyhow!("查单-获取 'data' 字段失败,原始 JSON: {}", value_str))
|
|
|
}
|
|
|
|
|
|
fn match_create_order_result(&self, create_result: &Result<Response>) -> Result<String> {
|