Skip to content

Commit 4960ab2

Browse files
committed
Enhance trade handling by introducing is_taker parameter to distinguish between active (taker) and passive (maker) orders. Update handle_success_result and trade recording logic to ensure only taker trades are recorded, preventing duplicate entries. Modify UserTradeView to include user direction and is_taker status for improved trade visibility in API responses. Update frontend to display trade type (主动成交/被动成交) based on is_taker status.
1 parent 0d5dfa1 commit 4960ab2

5 files changed

Lines changed: 165 additions & 57 deletions

File tree

src/exchange/order_router.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -912,7 +912,8 @@ impl OrderRouter {
912912
"🔍 Processing Accepted event for order {}",
913913
order_id
914914
);
915-
self.handle_success_result(order_id, order, success)?;
915+
// Accepted 事件不涉及成交记录,is_taker 参数无影响
916+
self.handle_success_result(order_id, order, success, true)?;
916917
handled_accepted = true;
917918
} else {
918919
log::debug!(
@@ -936,13 +937,14 @@ impl OrderRouter {
936937
// 我们需要更新对手单的状态(如果它属于我们管理的订单)
937938

938939
if !handled_trade {
939-
// 第一个事件:新订单的成交
940+
// 第一个事件:新订单的成交(taker - 主动方)
940941
log::debug!(
941-
"🔍 Processing NEW order trade: order_id={}, opposite={}",
942+
"🔍 Processing TAKER order trade: order_id={}, opposite={}",
942943
match_order_id,
943944
opposite_order_id
944945
);
945-
self.handle_success_result(order_id, order, success.clone())?;
946+
// ✨ is_taker=true: 主动方,记录成交到 TradeRecorder @yutiansut @quantaxis
947+
self.handle_success_result(order_id, order, success.clone(), true)?;
946948
handled_trade = true;
947949
} else {
948950
// 第二个事件:对手单(挂单方)的成交
@@ -967,10 +969,12 @@ impl OrderRouter {
967969
if let Some(maker_info) = self.orders.get(&maker_order_str) {
968970
let maker_order_data = maker_info.read().order.clone();
969971
// 处理挂单方的成交 - 更新其账户持仓和资金
972+
// ✨ is_taker=false: 被动方(maker),不记录成交到 TradeRecorder @yutiansut @quantaxis
970973
self.handle_success_result(
971974
&maker_order_str,
972975
&maker_order_data,
973976
success,
977+
false, // maker 不记录成交
974978
)?;
975979
}
976980
} else {
@@ -989,7 +993,8 @@ impl OrderRouter {
989993
}
990994
_ => {
991995
// 其他事件正常处理(Cancelled, Amended等)
992-
self.handle_success_result(order_id, order, success)?;
996+
// 不涉及成交记录,is_taker 参数无影响
997+
self.handle_success_result(order_id, order, success, true)?;
993998
}
994999
}
9951000
}
@@ -1026,11 +1031,15 @@ impl OrderRouter {
10261031
}
10271032

10281033
/// 处理成功的撮合结果 (Phase 6: 使用新的回报机制)
1034+
/// 处理成交结果
1035+
/// @yutiansut @quantaxis
1036+
/// is_taker: 是否为主动方(taker),只有 taker 才记录到 TradeRecorder
10291037
fn handle_success_result(
10301038
&self,
10311039
order_id: &str,
10321040
order: &Order,
10331041
success: Success,
1042+
is_taker: bool, // ✨ 是否为主动方
10341043
) -> Result<(), ExchangeError> {
10351044
match success {
10361045
Success::Accepted { id, order_type: _, ts } => {
@@ -1195,6 +1204,7 @@ impl OrderRouter {
11951204
opposite_user_id.as_deref(), // ✨ 传递对手方user_id
11961205
&qa_order_id, // ✨ 传递qars订单ID
11971206
opposite_order_id_str.as_deref(), // ✨ 传递对手方真实订单ID
1207+
is_taker, // ✨ 是否为主动方,只有 taker 记录成交 @yutiansut @quantaxis
11981208
)?;
11991209

12001210
log::debug!(
@@ -1305,6 +1315,7 @@ impl OrderRouter {
13051315
opposite_user_id.as_deref(), // ✨ 传递对手方user_id
13061316
&qa_order_id, // ✨ 传递qars订单ID
13071317
opposite_order_id_str.as_deref(), // ✨ 传递对手方真实订单ID
1318+
is_taker, // ✨ 是否为主动方,只有 taker 记录成交 @yutiansut @quantaxis
13081319
)?;
13091320

13101321
log::debug!(
@@ -1528,7 +1539,8 @@ impl OrderRouter {
15281539
log::info!("Cancel order success: {:?}", success);
15291540
// ✨ 调用 handle_success_result 处理撤单成功事件
15301541
// 这会触发 Success::Cancelled 分支,更新订单状态并释放冻结资金
1531-
if let Err(e) = self.handle_success_result(&req.order_id, &order, success) {
1542+
// 撤单不涉及成交记录,is_taker 参数无影响
1543+
if let Err(e) = self.handle_success_result(&req.order_id, &order, success, true) {
15321544
log::error!("Failed to handle cancel success result: {:?}", e);
15331545
}
15341546
}

src/exchange/trade_gateway.rs

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,8 @@ impl TradeGateway {
720720
///
721721
/// 交易所成交,推送Trade回报给账户(不判断FILLED/PARTIAL_FILLED)
722722
/// 账户端收到TRADE后自己计算 volume_left 判断状态
723+
/// @yutiansut @quantaxis
724+
/// is_taker: 是否为主动方(taker),只有 taker 才记录到 TradeRecorder(避免重复记录)
723725
pub fn handle_trade_new(
724726
&self,
725727
exchange: &str, // 交易所代码
@@ -735,6 +737,7 @@ impl TradeGateway {
735737
opposite_user_id: Option<&str>, // ✨ 对手方user_id,用于成交记录正确区分买卖方 @yutiansut @quantaxis
736738
qa_order_id: &str, // ✨ qars内部订单ID,用于调用receive_deal_sim @yutiansut @quantaxis
737739
opposite_order_id_str: Option<&str>, // ✨ 对手方订单ID字符串,用于成交记录 @yutiansut @quantaxis
740+
is_taker: bool, // ✨ 是否为主动方,只有 taker 记录到 TradeRecorder @yutiansut @quantaxis
738741
) -> Result<i64, ExchangeError> {
739742
// 生成成交ID(统一事件序列)
740743
let trade_id = self.id_generator.next_sequence(instrument_id);
@@ -792,46 +795,55 @@ impl TradeGateway {
792795
})?;
793796

794797
// 记录成交到 TradeRecorder(用于查询)
795-
// ✨ 修复:正确设置 buy_user_id 和 sell_user_id @yutiansut @quantaxis
796-
if let Some(recorder) = &self.trade_recorder {
797-
let trading_day = chrono::Utc::now().format("%Y-%m-%d").to_string();
798-
799-
// 根据 direction 确定买卖方的 user_id
800-
let (buy_user_id, sell_user_id) = match direction {
801-
"BUY" => {
802-
// 当前方是买方,对手方是卖方
803-
let sell_id = opposite_user_id.unwrap_or(user_id).to_string();
804-
(user_id.to_string(), sell_id)
805-
}
806-
"SELL" => {
807-
// 当前方是卖方,对手方是买方
808-
let buy_id = opposite_user_id.unwrap_or(user_id).to_string();
809-
(buy_id, user_id.to_string())
810-
}
811-
_ => (user_id.to_string(), user_id.to_string()), // fallback
812-
};
798+
// ✨ 修复:只有 taker 才记录成交,避免重复记录 @yutiansut @quantaxis
799+
// taker 是主动方(新下单的一方),maker 是被动方(挂在订单簿上的一方)
800+
if is_taker {
801+
if let Some(recorder) = &self.trade_recorder {
802+
let trading_day = chrono::Utc::now().format("%Y-%m-%d").to_string();
803+
804+
// 根据 direction 确定买卖方的 user_id
805+
let (buy_user_id, sell_user_id) = match direction {
806+
"BUY" => {
807+
// 当前方(taker)是买方,对手方(maker)是卖方
808+
let sell_id = opposite_user_id.unwrap_or(user_id).to_string();
809+
(user_id.to_string(), sell_id)
810+
}
811+
"SELL" => {
812+
// 当前方(taker)是卖方,对手方(maker)是买方
813+
let buy_id = opposite_user_id.unwrap_or(user_id).to_string();
814+
(buy_id, user_id.to_string())
815+
}
816+
_ => (user_id.to_string(), user_id.to_string()), // fallback
817+
};
813818

814-
// ✨ 根据 direction 确定 buy_order_id 和 sell_order_id @yutiansut @quantaxis
815-
let opposite_id = opposite_order_id_str
816-
.map(|s| s.to_string())
817-
.unwrap_or_else(|| format!("opposite_{}", opposite_order_id.unwrap_or(0)));
819+
// ✨ 根据 direction 确定 buy_order_id 和 sell_order_id @yutiansut @quantaxis
820+
let opposite_id = opposite_order_id_str
821+
.map(|s| s.to_string())
822+
.unwrap_or_else(|| format!("opposite_{}", opposite_order_id.unwrap_or(0)));
818823

819-
let (buy_order_id, sell_order_id) = match direction {
820-
"BUY" => (order_id.to_string(), opposite_id),
821-
"SELL" => (opposite_id, order_id.to_string()),
822-
_ => (order_id.to_string(), "unknown".to_string()),
823-
};
824+
let (buy_order_id, sell_order_id) = match direction {
825+
"BUY" => (order_id.to_string(), opposite_id),
826+
"SELL" => (opposite_id, order_id.to_string()),
827+
_ => (order_id.to_string(), "unknown".to_string()),
828+
};
824829

825-
recorder.record_trade(
826-
instrument_id.to_string(),
827-
buy_user_id, // ✨ 正确的买方user_id
828-
sell_user_id, // ✨ 正确的卖方user_id
829-
buy_order_id, // ✨ 正确的买方order_id
830-
sell_order_id, // ✨ 正确的卖方order_id
831-
price,
832-
volume,
833-
trading_day,
834-
);
830+
// taker_order_id 就是当前订单ID(主动方)
831+
let taker_order_id = order_id.to_string();
832+
833+
recorder.record_trade(
834+
instrument_id.to_string(),
835+
buy_user_id, // ✨ 正确的买方user_id
836+
sell_user_id, // ✨ 正确的卖方user_id
837+
buy_order_id, // ✨ 正确的买方order_id
838+
sell_order_id, // ✨ 正确的卖方order_id
839+
taker_order_id, // ✨ 主动方订单ID
840+
price,
841+
volume,
842+
trading_day,
843+
);
844+
}
845+
} else {
846+
log::debug!("🔍 Skipping trade record for maker (is_taker=false): order_id={}", order_id);
835847
}
836848

837849
// 更新快照生成器的成交统计

src/matching/trade_recorder.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use serde::{Deserialize, Serialize};
1010
use std::sync::Arc;
1111

1212
/// 成交记录
13+
/// @yutiansut @quantaxis
1314
#[derive(Debug, Clone, Serialize, Deserialize)]
1415
pub struct TradeRecord {
1516
pub trade_id: String,
@@ -18,6 +19,9 @@ pub struct TradeRecord {
1819
pub sell_user_id: String,
1920
pub buy_order_id: String,
2021
pub sell_order_id: String,
22+
/// 主动方(taker)订单ID - 订单号较大的是主动方
23+
/// 被动方(maker)订单ID是另一个(订单号较小)
24+
pub taker_order_id: String,
2125
pub price: f64,
2226
pub volume: f64,
2327
pub timestamp: i64,
@@ -50,13 +54,16 @@ impl TradeRecorder {
5054
}
5155

5256
/// 记录成交
57+
/// @yutiansut @quantaxis
58+
/// taker_order_id: 主动方订单ID(新下单的一方,订单号较大)
5359
pub fn record_trade(
5460
&self,
5561
instrument_id: String,
5662
buy_user_id: String,
5763
sell_user_id: String,
5864
buy_order_id: String,
5965
sell_order_id: String,
66+
taker_order_id: String,
6067
price: f64,
6168
volume: f64,
6269
trading_day: String,
@@ -71,6 +78,7 @@ impl TradeRecorder {
7178
sell_user_id: sell_user_id.clone(),
7279
buy_order_id,
7380
sell_order_id,
81+
taker_order_id,
7482
price,
7583
volume,
7684
timestamp,
@@ -220,12 +228,14 @@ mod tests {
220228
fn test_trade_recorder() {
221229
let recorder = TradeRecorder::new();
222230

231+
// order2 是 taker(主动方,订单号较大)
223232
let trade_id = recorder.record_trade(
224233
"TEST2301".to_string(),
225234
"user1".to_string(),
226235
"user2".to_string(),
227236
"order1".to_string(),
228237
"order2".to_string(),
238+
"order2".to_string(), // taker_order_id
229239
100.0,
230240
10.0,
231241
"2025-10-03".to_string(),
@@ -239,6 +249,7 @@ mod tests {
239249
let trade = trade.unwrap();
240250
assert_eq!(trade.price, 100.0);
241251
assert_eq!(trade.volume, 10.0);
252+
assert_eq!(trade.taker_order_id, "order2");
242253
}
243254

244255
#[test]
@@ -251,6 +262,7 @@ mod tests {
251262
"user2".to_string(),
252263
"order1".to_string(),
253264
"order2".to_string(),
265+
"order2".to_string(), // taker
254266
100.0,
255267
10.0,
256268
"2025-10-03".to_string(),
@@ -262,6 +274,7 @@ mod tests {
262274
"user3".to_string(),
263275
"order3".to_string(),
264276
"order4".to_string(),
277+
"order4".to_string(), // taker
265278
101.0,
266279
20.0,
267280
"2025-10-03".to_string(),
@@ -281,6 +294,7 @@ mod tests {
281294
"user2".to_string(),
282295
"order1".to_string(),
283296
"order2".to_string(),
297+
"order2".to_string(), // taker
284298
100.0,
285299
10.0,
286300
"2025-10-03".to_string(),
@@ -292,6 +306,7 @@ mod tests {
292306
"user3".to_string(),
293307
"order3".to_string(),
294308
"order4".to_string(),
309+
"order4".to_string(), // taker
295310
110.0,
296311
20.0,
297312
"2025-10-03".to_string(),

0 commit comments

Comments
 (0)