File size: 3,817 Bytes
a3b10ab | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | #include "actors/ClearingHouseActor.hpp"
#include <cstring>
#include <algorithm>
namespace eunex {
ClearingHouseActor::ClearingHouseActor() {
registerEventHandler<TradeEvent>(*this);
initMembers();
}
void ClearingHouseActor::initMembers() {
for (int i = 0; i < NUM_MEMBERS; ++i) {
MemberId_t id = static_cast<MemberId_t>(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<std::mutex> lock(mutex_);
sessionToMember_[sessionId] = memberId;
}
void ClearingHouseActor::onEvent(const TradeEvent& event) {
std::lock_guard<std::mutex> 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<double>(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<int64_t>(qty) : -static_cast<int64_t>(qty);
h.avgCost = price;
m.holdings[symbolIdx] = h;
m.distinctSymbols = static_cast<int>(m.holdings.size());
} else {
MemberHolding& h = hIt->second;
if (isBuy) {
double prevCost = toDouble(h.avgCost) * static_cast<double>(std::abs(h.quantity));
h.quantity += static_cast<int64_t>(qty);
if (h.quantity != 0) {
h.avgCost = toFixedPrice((prevCost + cost) / static_cast<double>(std::abs(h.quantity)));
}
} else {
h.quantity -= static_cast<int64_t>(qty);
if (h.quantity == 0) {
m.holdings.erase(hIt);
m.distinctSymbols = static_cast<int>(m.holdings.size());
}
}
}
}
std::vector<LeaderboardEntry> ClearingHouseActor::getLeaderboard() const {
std::lock_guard<std::mutex> lock(mutex_);
std::vector<LeaderboardEntry> 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<int>(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<std::mutex> lock(mutex_);
auto it = members_.find(id);
return (it != members_.end()) ? &it->second : nullptr;
}
} // namespace eunex
|