Skip to main content

futu_cache/trd_cache/
order_fill_upsert.rs

1use futu_domain_trade_order::{
2    FillSnapshotReplacementPlan, FillUpsertAction, TradeFillUpdateFacts,
3    fill_identity_matches_like_cpp, plan_fill_snapshot_replacement_like_cpp,
4    plan_fill_upsert_like_cpp,
5};
6
7use super::{CachedOrderFill, TrdCache};
8
9impl TrdCache {
10    /// Apply C++ `UpdateDealList` to a fully paged current-fill snapshot.
11    ///
12    /// Planning and replacement share one DashMap entry guard so a direct fill
13    /// push cannot observe or mutate a half-replaced snapshot.
14    pub fn replace_order_fill_snapshot_like_cpp(
15        &self,
16        acc_id: u64,
17        incoming: Vec<CachedOrderFill>,
18    ) -> FillSnapshotReplacementPlan {
19        let mut entry = self.order_fills.entry(acc_id).or_default();
20        let existing_facts = entry.iter().map(Self::fill_facts).collect::<Vec<_>>();
21        let incoming_facts = incoming.iter().map(Self::fill_facts).collect::<Vec<_>>();
22        let plan = plan_fill_snapshot_replacement_like_cpp(&existing_facts, &incoming_facts);
23        *entry = incoming;
24        plan
25    }
26
27    /// Apply C++ `UpdateAndNotifyOneDeal` admission to the current fill cache.
28    /// Returns true only when callers should emit `Trd_UpdateOrderFill`.
29    pub fn upsert_order_fill(&self, acc_id: u64, fill: CachedOrderFill) -> bool {
30        let mut entry = self.order_fills.entry(acc_id).or_default();
31        if let Some(existing) = entry.iter_mut().find(|existing| {
32            fill_identity_matches_like_cpp(Self::fill_facts(existing), Self::fill_facts(&fill))
33        }) {
34            match plan_fill_upsert_like_cpp(
35                Some(Self::fill_facts(existing)),
36                Self::fill_facts(&fill),
37            ) {
38                FillUpsertAction::ReplaceExisting => {
39                    *existing = fill;
40                    true
41                }
42                FillUpsertAction::IgnoreUnchanged | FillUpsertAction::InsertNew => false,
43            }
44        } else {
45            entry.push(fill);
46            true
47        }
48    }
49
50    fn fill_facts(fill: &CachedOrderFill) -> TradeFillUpdateFacts<'_> {
51        TradeFillUpdateFacts {
52            fill_id: fill.fill_id,
53            fill_id_ex: &fill.fill_id_ex,
54            status: fill.status,
55        }
56    }
57}