6#include <unordered_map>
10#include "../core/types.hpp"
15namespace order_update_detail {
35inline bool same_number(
const Decimal64& lhs,
const Decimal64& rhs) {
40inline bool same_number(
41 const std::optional<Decimal64>& lhs,
const std::optional<Decimal64>& rhs
43 if (lhs.has_value() != rhs.has_value()) {
46 return !lhs.has_value() || same_number(*lhs, *rhs);
56inline bool same_observable_state(
const OrderSnapshot& lhs,
const OrderSnapshot& rhs) {
57 return lhs.status_ == rhs.status_ &&
58 same_number(lhs.execution_.filled_quantity_, rhs.execution_.filled_quantity_) &&
59 same_number(lhs.price_, rhs.price_) &&
60 same_number(lhs.trigger_price_, rhs.trigger_price_) &&
61 same_number(lhs.quantity_, rhs.quantity_) &&
62 same_number(lhs.order_amount_, rhs.order_amount_) &&
63 lhs.canceled_at_ == rhs.canceled_at_;
96template <
typename Broker>
111 return observe(rows,
true);
120 observe(rows,
false);
149 bool contradicted_{
false};
158 std::vector<OrderSnapshot> observe(
159 const std::vector<WorkingOrder<Broker>>& rows,
bool report
161 std::vector<Tracked> next;
162 next.reserve(rows.size());
168 std::unordered_map<OrderRef<Broker>, std::size_t> built;
169 built.reserve(rows.size());
170 std::unordered_map<OrderRef<Broker>, std::size_t> held_at;
171 held_at.reserve(tracked_.size());
172 for (std::size_t at = 0; at < tracked_.size(); ++at) {
173 held_at.emplace(tracked_[at].ref_, at);
176 for (
const auto& row : rows) {
182 if (row.ref_.primary_.empty() && row.ref_.secondary_.empty()) {
186 const auto [at, first] = built.try_emplace(row.ref_, next.size());
188 next.push_back(Tracked{row.ref_, row.order_,
false});
192 auto& already = next[at->second];
193 if (!order_update_detail::same_observable_state(already.last_, row.order_)) {
195 already.contradicted_ =
true;
199 std::vector<OrderSnapshot> updates;
200 for (
const auto& entry : next) {
201 if (entry.contradicted_) {
205 const auto found = held_at.find(entry.ref_);
206 const Tracked* held = found == held_at.end() ? nullptr : &tracked_[found->second];
208 held ==
nullptr || !order_update_detail::same_observable_state(held->last_, entry.last_);
209 if (report && differs) {
210 updates.push_back(entry.last_);
220 [](
const Tracked& entry) { return entry.contradicted_; }
224 tracked_ = std::move(next);
228 std::vector<Tracked> tracked_;
229 std::size_t untracked_{0};
230 std::size_t contradicted_{0};
Turns successive working-order listings into order updates: the rows that changed since the previous ...
std::size_t contradicted_rows() const noexcept
Returns how many times a listing stated one order twice with disagreeing readings (and so it was not ...
std::size_t untracked_rows() const noexcept
Returns how many rows had an empty reference, and so were never reported.
void adopt(const std::vector< WorkingOrder< Broker > > &rows)
Takes a listing as the baseline without reporting anything (such as the startup read,...
std::vector< OrderSnapshot > changed(const std::vector< WorkingOrder< Broker > > &rows)
Compares a listing with the previous one and returns the rows that changed.
std::size_t tracked_orders() const noexcept
Returns how many orders the watch is tracking.
Runs a strategy: the runner, the polling loop, the order journal, and stopping.
The library: broker-neutral types (core), and the modules below.
bool decimal_less(const Decimal64 &lhs, const Decimal64 &rhs)
Compares two decimals numerically, whatever their scales.
A broker's reference to one order, used to amend or cancel it.
The state of one order, as a broker listing reported it.
An order still open to modification or cancellation.