3#include "./portfolio.hpp"
5#include <algotradelib/core>
40 return "undetermined";
42 return "net_of_resting";
44 return "gross_of_resting";
46 return "inconsistent";
48 return "undetermined";
103template <
typename Broker>
118 for (
const auto& position : portfolio.
positions_) {
120 if (!reading.basis_.is_enforceable()) {
129 forget(position.instrument_);
132 if (!position.sellable_quantity_) {
136 const auto resting = reported_resting(portfolio, position.instrument_);
137 const Reading now{position.quantity_, *position.sellable_quantity_, resting};
138 if (
auto* previous = find(last_, position.instrument_)) {
139 judge(position.instrument_, *previous, now);
143 last_.push_back({position.instrument_, now});
153 for (
auto it = last_.begin(); it != last_.end(); ++it) {
154 if (it->first == instrument) {
167 if (
const auto* found = find(evidence_, instrument)) {
179 for (
const auto& entry : evidence_) {
180 total.
net_ += entry.second.net_;
181 total.
gross_ += entry.second.gross_;
196 const std::vector<std::pair<InstrumentId, SellableEvidence>>&
per_instrument() const noexcept {
213 for (
const auto& order : portfolio.
working_) {
214 if (order.reserved_ || !(order.order_.instrument_ == instrument) ||
215 order.order_.side_ != OrderSide::SELL) {
222 order.order_.quantity_, order.order_.execution_.filled_quantity_
227 if (
const auto sum =
decimal_add(total, *remaining)) {
242 static bool same(
const Decimal64& lhs,
const Decimal64& rhs) {
250 void judge(
const InstrumentId& instrument,
const Reading& before,
const Reading& now) {
251 if (!same(before.held_, now.held_)) {
260 if (!gap_before || !gap_now) {
268 auto* entry = find(evidence_, instrument);
269 if (entry ==
nullptr) {
270 evidence_.push_back({instrument, SellableEvidence{}});
271 entry = &evidence_.back().second;
273 if (same(*moved, *grew)) {
283 template <
typename Entries>
284 static auto find(Entries& entries,
const InstrumentId& instrument)
285 ->
decltype(&entries.front().second) {
286 for (
auto& entry : entries) {
287 if (entry.first == instrument) {
288 return &entry.second;
294 std::vector<std::pair<InstrumentId, Reading>> last_;
295 std::vector<std::pair<InstrumentId, SellableEvidence>> evidence_;
An exact signed decimal: an int64 coefficient times 10^-scale.
static Decimal64 parse(std::string_view input)
Parses a decimal string exactly (no binary floating point).
Infers a broker's SellableConvention from successive portfolios.
SellableEvidence evidence(const InstrumentId &instrument) const
Returns the evidence for one instrument.
SellableConvention verdict() const
Returns the broker's convention as observed so far.
SellableEvidence overall() const
Returns the evidence summed over every instrument.
const std::vector< std::pair< InstrumentId, SellableEvidence > > & per_instrument() const noexcept
Returns the evidence per instrument.
void observe(const Portfolio< Broker > &portfolio)
Records one polled portfolio, comparing it with the previous one.
void forget(const InstrumentId &instrument)
Discards the last recorded reading for an instrument, so the next one is not compared across a gap.
What a strategy sees and emits: events, intents, the portfolio, reconciliation and risk limits.
SellableConvention
Whether a broker's sellable quantity already excludes sell orders resting at the broker.
@ INCONSISTENT
Both behaviours were observed; no single rule fits.
@ GROSS_OF_RESTING
The figure did not move when a sell began resting: the broker includes them.
@ NET_OF_RESTING
The figure fell when a sell began resting: the broker excludes resting sells.
@ UNDETERMINED
Nothing conclusive has been observed yet.
bool order_is_open(OrderStatus status)
Tests whether an order in a given status may still trade.
constexpr std::string_view sellable_convention_name(SellableConvention convention) noexcept
Returns a lowercase name for a convention, such as "net_of_resting", for logs.
The library: broker-neutral types (core), and the modules below.
std::optional< Decimal64 > decimal_add(const Decimal64 &lhs, const Decimal64 &rhs)
Adds two decimals exactly.
std::optional< Decimal64 > decimal_subtract(const Decimal64 &lhs, const Decimal64 &rhs)
Subtracts two decimals exactly.
bool decimal_less(const Decimal64 &lhs, const Decimal64 &rhs)
Compares two decimals numerically, whatever their scales.
Identifies an instrument: its country, venue and symbol.
What the account holds and which orders are still working, as a strategy sees it.
std::vector< WorkingOrder< Broker > > working_
Orders still outstanding at the broker.
SellableReading sellable_reading_for(const InstrumentId &instrument) const
Returns an instrument's sellable quantity and its basis, taken from the same row.
std::vector< HoldingPosition > positions_
Every position row the broker reported.
How many observations supported each answer.
std::size_t total() const noexcept
Returns the number of observations.
std::size_t gross_
Observations where the figure did not move when a sell began resting.
SellableConvention verdict() const noexcept
Returns the convention the counts support.
std::size_t net_
Observations where the figure fell by the quantity that began resting.