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