#include "actors/ClearingHouseActor.hpp" #include #include namespace eunex { ClearingHouseActor::ClearingHouseActor() { registerEventHandler(*this); initMembers(); } void ClearingHouseActor::initMembers() { for (int i = 0; i < NUM_MEMBERS; ++i) { MemberId_t id = static_cast(i + 1); MemberState ms{}; ms.memberId = id; std::snprintf(ms.name, sizeof(ms.name), "MBR%02d", i + 1); ms.capital = INITIAL_CAPITAL; ms.initialCapital = INITIAL_CAPITAL; ms.tradeCount = 0; ms.distinctSymbols = 0; members_[id] = std::move(ms); } } void ClearingHouseActor::mapSession(SessionId_t sessionId, MemberId_t memberId) { std::lock_guard lock(mutex_); sessionToMember_[sessionId] = memberId; } void ClearingHouseActor::onEvent(const TradeEvent& event) { std::lock_guard lock(mutex_); const Trade& t = event.trade; auto buyIt = sessionToMember_.find(t.buySessionId); if (buyIt != sessionToMember_.end()) { processTradeSide(buyIt->second, t.symbolIdx, t.price, t.quantity, true); } auto sellIt = sessionToMember_.find(t.sellSessionId); if (sellIt != sessionToMember_.end()) { processTradeSide(sellIt->second, t.symbolIdx, t.price, t.quantity, false); } } void ClearingHouseActor::processTradeSide(MemberId_t memberId, SymbolIndex_t symbolIdx, Price_t price, Quantity_t qty, bool isBuy) { auto it = members_.find(memberId); if (it == members_.end()) return; MemberState& m = it->second; m.tradeCount++; double cost = toDouble(price) * static_cast(qty); if (isBuy) { m.capital -= cost; } else { m.capital += cost; } auto hIt = m.holdings.find(symbolIdx); if (hIt == m.holdings.end()) { MemberHolding h{}; h.symbolIdx = symbolIdx; h.quantity = isBuy ? static_cast(qty) : -static_cast(qty); h.avgCost = price; m.holdings[symbolIdx] = h; m.distinctSymbols = static_cast(m.holdings.size()); } else { MemberHolding& h = hIt->second; if (isBuy) { double prevCost = toDouble(h.avgCost) * static_cast(std::abs(h.quantity)); h.quantity += static_cast(qty); if (h.quantity != 0) { h.avgCost = toFixedPrice((prevCost + cost) / static_cast(std::abs(h.quantity))); } } else { h.quantity -= static_cast(qty); if (h.quantity == 0) { m.holdings.erase(hIt); m.distinctSymbols = static_cast(m.holdings.size()); } } } } std::vector ClearingHouseActor::getLeaderboard() const { std::lock_guard lock(mutex_); std::vector entries; entries.reserve(members_.size()); for (auto& [id, ms] : members_) { LeaderboardEntry e{}; e.memberId = ms.memberId; std::memcpy(e.name, ms.name, sizeof(e.name)); e.capital = ms.capital; e.pnl = ms.capital - ms.initialCapital; e.tradeCount = ms.tradeCount; e.holdingCount = static_cast(ms.holdings.size()); entries.push_back(e); } std::sort(entries.begin(), entries.end(), [](const LeaderboardEntry& a, const LeaderboardEntry& b) { return a.capital > b.capital; }); return entries; } const MemberState* ClearingHouseActor::getMember(MemberId_t id) const { std::lock_guard lock(mutex_); auto it = members_.find(id); return (it != members_.end()) ? &it->second : nullptr; } } // namespace eunex