algotradelib 0.0.0.9000
C++ header-only library for algorithmic trading
Loading...
Searching...
No Matches
journal.hpp
1#pragma once
2
3#include "./clock.hpp"
4#include "./execution.hpp"
5
7
8#include <algotradelib/core>
9
10#include <algorithm>
11#include <chrono>
12#include <cstddef>
13#include <cstdint>
14#include <iterator>
15#include <optional>
16#include <string>
17#include <string_view>
18#include <utility>
19#include <vector>
20
21namespace algotradelib {
22namespace runner {
23
30enum class JournalAction {
32 PLACE,
34 CANCEL,
35};
36
38inline constexpr std::array<JournalAction, 2> all_journal_actions{JournalAction::PLACE, JournalAction::CANCEL};
39
45inline constexpr std::string_view journal_action_name(JournalAction action) noexcept {
46 switch (action) {
48 return "place";
50 return "cancel";
51 }
52 return "";
53}
54
55static_assert(
56 lists_every_value(all_journal_actions, [](JournalAction action) { return !journal_action_name(action).empty(); }),
57 "all_journal_actions must list every JournalAction"
58);
59
67inline constexpr bool journal_action_matches_by_order_id(JournalAction action) noexcept {
68 switch (action) {
70 return true;
72 return false;
73 }
74 return false;
75}
76
82inline std::optional<JournalAction> journal_action_from(std::string_view text) noexcept {
84}
85
131
142
148inline constexpr std::string_view journal_outcome_name(JournalOutcome outcome) noexcept {
149 switch (outcome) {
151 return "pending";
153 return "accepted";
155 return "rejected";
157 return "indeterminate";
159 return "resolved";
161 return "confirmed";
163 return "held";
164 }
165 return "";
166}
167
168static_assert(
169 lists_every_value(all_journal_outcomes, [](JournalOutcome outcome) { return !journal_outcome_name(outcome).empty(); }),
170 "all_journal_outcomes must list every JournalOutcome"
171);
172
178inline std::optional<JournalOutcome> journal_outcome_from(std::string_view text) noexcept {
180}
181
190inline constexpr JournalOutcome journal_outcome_of(SendOutcome outcome) noexcept {
191 switch (outcome) {
199 // Nothing was sent, so the order does not exist.
202 // Nothing was sent, so the order does not exist.
204 }
206}
207
213inline constexpr bool journal_outcome_is_terminal(JournalOutcome outcome) noexcept {
214 switch (outcome) {
216 return false;
223 return true;
224 }
225 return true;
226}
227
234inline constexpr bool journal_outcome_answers_send(JournalOutcome outcome) noexcept {
235 switch (outcome) {
239 return true;
244 return false;
245 }
246 return false;
247}
248
254inline constexpr bool journal_outcome_names_order(JournalOutcome outcome) noexcept {
255 switch (outcome) {
258 return true;
264 return false;
265 }
266 return false;
267}
268
274inline constexpr bool journal_outcome_refuses(JournalOutcome outcome) noexcept {
275 switch (outcome) {
277 return true;
284 return false;
285 }
286 return false;
287}
288
295inline constexpr bool journal_outcome_is_closing_account(JournalOutcome outcome) noexcept {
296 switch (outcome) {
299 return true;
305 return false;
306 }
307 return false;
308}
309
316inline constexpr bool journal_outcome_requires_operator(JournalOutcome outcome) noexcept {
317 switch (outcome) {
319 return true;
326 return false;
327 }
328 return false;
329}
330
338inline constexpr bool journal_outcome_leaves_open(JournalOutcome outcome) noexcept {
339 switch (outcome) {
342 return true;
348 return false;
349 }
350 return true;
351}
352
366 std::string id_;
372 std::chrono::system_clock::time_point recorded_at_{};
376 OrderSide side_{OrderSide::BUY};
390 std::optional<Venue> venue_{Venue::UNSPECIFIED};
394 std::optional<Decimal64> price_;
396 std::optional<Decimal64> trigger_price_;
403 std::optional<Decimal64> baseline_;
408 std::string order_id_;
410 std::string detail_;
424 std::string scope_;
425};
426
441
447inline constexpr std::string_view journal_read_status_name(JournalReadStatus status) noexcept {
448 switch (status) {
450 return "missing";
452 return "read";
454 return "unreadable";
455 }
456 return "unknown";
457}
458
466 std::vector<JournalEntry> entries_;
468 std::size_t unreadable_lines_{0};
470 bool truncated_tail_{false};
472 std::string detail_;
474 std::string scope_;
476 bool has_header_{false};
479
484 bool readable() const noexcept {
485 switch (status_) {
488 return true;
490 return false;
491 }
492 return false;
493 }
494
499 bool intact() const noexcept {
500 return readable() && unreadable_lines_ == 0 && !truncated_tail_;
501 }
502};
503
514 std::chrono::system_clock::time_point opened_at_{};
519 std::optional<std::chrono::system_clock::time_point> closed_at_;
521 bool answered_{false};
523 std::string detail_;
524};
525
537inline std::vector<OpenInstruction> unresolved_instructions(const JournalReplay& replay) {
538 std::vector<OpenInstruction> open;
539 for (const auto& entry : replay.entries_) {
540 if (!journal_outcome_is_terminal(entry.outcome_)) {
541 OpenInstruction instruction;
542 instruction.entry_ = entry;
543 instruction.opened_at_ = entry.recorded_at_;
544 instruction.detail_ = entry.detail_;
545 open.push_back(std::move(instruction));
546 continue;
547 }
548
549 bool paired = false;
550 for (auto at = open.begin(); at != open.end(); ++at) {
551 if (at->entry_.id_ != entry.id_) {
552 continue;
553 }
554 paired = true;
555 if (journal_outcome_leaves_open(entry.outcome_)) {
556 at->answered_ = true;
557 at->closed_at_ = entry.recorded_at_;
558 at->detail_ = entry.detail_;
559 // The broker issued no reference, so the placement keeps the one its pending line had.
560 at->entry_.order_id_ = entry.order_id_.empty() ? at->entry_.order_id_ : entry.order_id_;
561 } else {
562 open.erase(at);
563 }
564 break;
565 }
566 if (!paired && journal_outcome_leaves_open(entry.outcome_)) {
567 OpenInstruction instruction;
568 instruction.entry_ = entry;
569 instruction.opened_at_ = entry.recorded_at_;
570 instruction.closed_at_ = entry.recorded_at_;
571 instruction.answered_ = true;
572 instruction.detail_ = entry.detail_;
573 open.push_back(std::move(instruction));
574 }
575 }
576 return open;
577}
578
592inline std::vector<OpenInstruction> placements_of(const JournalReplay& replay, const std::vector<std::string>& ids) {
593 std::vector<OpenInstruction> found;
594 for (const auto& entry : replay.entries_) {
595 if (entry.action_ != JournalAction::PLACE || entry.requires_operator_ ||
596 !journal_outcome_leaves_open(entry.outcome_) ||
597 std::find(ids.begin(), ids.end(), entry.id_) == ids.end()) {
598 continue;
599 }
600 auto known = std::find_if(found.begin(), found.end(), [&](const OpenInstruction& instruction) {
601 return instruction.entry_.id_ == entry.id_;
602 });
603 if (known == found.end()) {
604 OpenInstruction instruction;
605 instruction.entry_ = entry;
606 instruction.opened_at_ = entry.recorded_at_;
607 instruction.detail_ = entry.detail_;
608 found.push_back(std::move(instruction));
609 known = std::prev(found.end());
610 }
611 if (journal_outcome_is_terminal(entry.outcome_)) {
612 known->answered_ = true;
613 known->closed_at_ = entry.recorded_at_;
614 known->detail_ = entry.detail_;
615 }
616 }
617 return found;
618}
619
624public:
626 MemoryJournal() = default;
627
632 explicit MemoryJournal(std::string scope) : scope_(std::move(scope)) {}
633
639 bool append(const JournalEntry& entry) {
640 entries_.push_back(entry);
641 if (entries_.back().scope_.empty()) {
642 entries_.back().scope_ = scope_;
643 }
644 return true;
645 }
646
653 replay.entries_ = entries_;
654 return replay;
655 }
656
661 const std::vector<JournalEntry>& records() const noexcept { return entries_; }
662
664 void clear() noexcept { entries_.clear(); }
665
670 const std::string& scope() const noexcept { return scope_; }
671
672private:
673 std::vector<JournalEntry> entries_;
674 std::string scope_;
675};
676
694template <typename Inner, typename Journal, typename Clock = SteadyClock>
696public:
698 static constexpr bool reaches_a_broker = runner_detail::sends_to_a_broker<Inner>::value;
699
706 JournalingExecutor(Inner inner, Journal& journal, Clock clock = {})
707 : inner_(std::move(inner)), journal_(&journal), clock_(std::move(clock)) {
708 prefix_ = default_prefix();
709 }
710
721 void set_id_prefix(std::string prefix) { prefix_ = std::move(prefix); }
722
733 template <typename E = Inner>
734 auto route_of(const strategy::PlannedOrder& order, int) const
735 -> decltype(std::declval<const E&>().effective_route(order.venue_)) {
736 return inner_.effective_route(order.venue_);
737 }
738
745 Venue route_of(const strategy::PlannedOrder& order, long) const { return order.venue_; }
746
753 return route_of(order, 0);
754 }
755
761 SendOutcome place(const strategy::PlannedOrder& order) { return place(order, std::nullopt); }
762
770 SendOutcome place(const strategy::PlannedOrder& order, std::optional<Decimal64> baseline) {
771 JournalEntry entry;
772 entry.id_ = next_id();
775 entry.recorded_at_ = clock_.now();
776 entry.instrument_ = order.instrument_;
777 entry.side_ = order.side_;
778 entry.type_ = order.type_;
779 entry.time_in_force_ = order.time_in_force_;
780 entry.session_ = order.session_;
781 // Where the order will actually go (an unrouted KIS order reaches KRX), asked of the binding;
782 // a pure function of the order, so the line is still written before any I/O.
783 entry.venue_ = effective_route_of(order);
784 entry.quantity_ = order.quantity_;
785 entry.price_ = order.price_;
786 entry.trigger_price_ = order.trigger_price_;
787 entry.baseline_ = std::move(baseline);
788 if (!journal_->append(entry)) {
789 return refuse_unjournaled();
790 }
791
792 const auto outcome = inner_.place(order);
793
794 entry.outcome_ = journal_outcome_of(outcome);
795 entry.recorded_at_ = clock_.now();
796 entry.order_id_ = accepted_order_id(outcome);
797 entry.detail_ = failure_detail(outcome);
798 last_entry_ = entry;
799 if (!journal_->append(entry)) {
800 // The send happened; only its answer is lost, so recovery will see it unresolved. Recorded so
801 // the runner stops.
802 note_failure("the order journal could not record an instruction's outcome");
803 }
804 return outcome;
805 }
806
812 const std::optional<JournalEntry>& last_entry() const noexcept { return last_entry_; }
813
823 bool record(JournalEntry& entry) {
824 entry.recorded_at_ = clock_.now();
825 if (journal_->append(entry)) {
826 return true;
827 }
828 note_failure("the order journal could not record that a placement was accounted for");
829 return false;
830 }
831
838 template <typename BrokerTag>
840 JournalEntry entry;
841 entry.id_ = next_id();
844 entry.recorded_at_ = clock_.now();
845 entry.instrument_ = working.order_.instrument_;
846 entry.side_ = working.order_.side_;
847 entry.type_ = working.order_.type_;
848 entry.quantity_ = working.order_.quantity_;
849 entry.price_ = working.order_.price_;
850 entry.trigger_price_ = working.order_.trigger_price_;
851 // Known from the start: a cancellation names an existing order.
852 entry.order_id_ = working.ref_.primary_;
853 if (!journal_->append(entry)) {
854 return refuse_unjournaled();
855 }
856
857 const auto outcome = inner_.cancel(working);
858
859 entry.outcome_ = journal_outcome_of(outcome);
860 entry.recorded_at_ = clock_.now();
861 entry.detail_ = failure_detail(outcome);
862 if (!journal_->append(entry)) {
863 note_failure("the order journal could not record an instruction's outcome");
864 }
865 return outcome;
866 }
867
872 const Inner& inner() const noexcept { return inner_; }
877 Inner& inner() noexcept { return inner_; }
878
883 const Journal& journal() const noexcept { return *journal_; }
884
889 const std::string& last_journal_error() const noexcept { return journal_error_; }
890
895 std::size_t unjournaled_refusals() const noexcept { return refusals_; }
896
902 std::size_t journal_failures() const noexcept { return failures_; }
903
910 template <typename Executor = Inner>
911 auto requested_route(Venue asked) const noexcept
912 -> decltype(std::declval<const Executor&>().requested_route(asked)) {
913 return inner_.requested_route(asked);
914 }
915
921 template <typename Executor = Inner>
922 auto last_ref() const noexcept -> decltype(std::declval<const Executor&>().last_ref()) {
923 return inner_.last_ref();
924 }
925
931 template <typename Executor = Inner>
932 auto last_error() const noexcept -> decltype(std::declval<const Executor&>().last_error()) {
933 return inner_.last_error();
934 }
935
936private:
937 // Refuses an instruction that could not be recorded, without attempting it.
938 SendOutcome refuse_unjournaled() {
939 ++refusals_;
940 note_failure("the order journal could not be written, so nothing was sent");
942 }
943
944 // Records why the journal failed, keeping the first reason and counting every failure.
945 //
946 // The two halves answer different questions. The reason is for a person reading a report, and the
947 // first one is the useful one. The count is for the runner, which needs to know whether anything
948 // has gone wrong *since* it last acknowledged a problem.
949 void note_failure(std::string detail) {
950 ++failures_;
951 if (journal_error_.empty()) {
952 journal_error_ = std::move(detail);
953 }
954 }
955
956 // Returns a line id unique within this process and, by its prefix, across restarts.
957 std::string next_id() { return prefix_ + '-' + std::to_string(++sequence_); }
958
959 // Returns a prefix derived from the moment of construction, on the wall clock rather than `clock_`:
960 // the prefix tells process runs apart, and an injected clock (a test's, a replay's) may start two
961 // runs at the same instant.
962 std::string default_prefix() const {
963 const auto since = std::chrono::system_clock::now().time_since_epoch();
964 const auto micros = std::chrono::duration_cast<std::chrono::microseconds>(since).count();
965 return std::to_string(static_cast<std::int64_t>(micros));
966 }
967
968 // Returns the broker's id for an accepted order, where the inner executor reports one.
969 //
970 // Detected rather than required, because `RecordingExecutor` has no references to report and must
971 // still be wrappable — it is what every journal test runs against.
972 std::string accepted_order_id(SendOutcome outcome) const {
973 switch (outcome) {
975 return accepted_order_id_impl(0);
980 return {};
981 }
982 return {};
983 }
984
985 template <typename Executor = Inner>
986 auto accepted_order_id_impl(int) const
987 -> decltype(std::declval<const Executor&>().last_ref(), std::string()) {
988 const auto& ref = inner_.last_ref();
989 return ref ? ref->primary_ : std::string();
990 }
991
992 std::string accepted_order_id_impl(...) const { return {}; }
993
994 // Returns what the inner executor said went wrong, where it says anything.
995 std::string failure_detail(SendOutcome outcome) const {
996 switch (outcome) {
998 return {};
1003 return failure_detail_impl(0);
1004 }
1005 return failure_detail_impl(0);
1006 }
1007
1008 template <typename Executor = Inner>
1009 auto failure_detail_impl(int) const
1010 -> decltype(std::declval<const Executor&>().last_error(), std::string()) {
1011 const auto& error = inner_.last_error();
1012 return error ? error->message_ : std::string();
1013 }
1014
1015 std::string failure_detail_impl(...) const { return {}; }
1016
1017 Inner inner_;
1018 Journal* journal_;
1019 Clock clock_;
1020 std::optional<JournalEntry> last_entry_;
1021 std::string prefix_;
1022 std::string journal_error_;
1023 std::size_t refusals_{0};
1024 std::size_t failures_{0};
1025 std::uint64_t sequence_{0};
1026};
1027
1028} // namespace runner
1029} // namespace algotradelib
An exact signed decimal: an int64 coefficient times 10^-scale.
Definition types.hpp:297
auto last_ref() const noexcept -> decltype(std::declval< const Executor & >().last_ref())
Returns the reference of the last order the wrapped executor placed.
Definition journal.hpp:922
SendOutcome cancel(const WorkingOrder< BrokerTag > &working)
Records and sends one cancellation.
Definition journal.hpp:839
std::size_t unjournaled_refusals() const noexcept
Returns how many instructions were not sent because their PENDING line could not be written.
Definition journal.hpp:895
Inner & inner() noexcept
Returns the wrapped executor.
Definition journal.hpp:877
Venue route_of(const strategy::PlannedOrder &order, long) const
Returns the venue an order asked for, when the wrapped executor cannot resolve routes (the fallback o...
Definition journal.hpp:745
const std::optional< JournalEntry > & last_entry() const noexcept
Returns the answering line last written (or attempted) for a placement the wrapped executor was asked...
Definition journal.hpp:812
std::size_t journal_failures() const noexcept
Returns how many journal writes have failed; Runner compares it with the count it last acknowledged t...
Definition journal.hpp:902
const std::string & last_journal_error() const noexcept
Returns the first journal failure's description.
Definition journal.hpp:889
Venue effective_route_of(const strategy::PlannedOrder &order) const
Returns the venue to record for an order: the binding's route, or the venue asked for.
Definition journal.hpp:752
auto route_of(const strategy::PlannedOrder &order, int) const -> decltype(std::declval< const E & >().effective_route(order.venue_))
Returns the venue the wrapped executor says an order will reach.
Definition journal.hpp:734
const Journal & journal() const noexcept
Returns the journal.
Definition journal.hpp:883
void set_id_prefix(std::string prefix)
Sets the prefix of line ids.
Definition journal.hpp:721
SendOutcome place(const strategy::PlannedOrder &order)
Records and places one order.
Definition journal.hpp:761
static constexpr bool reaches_a_broker
Whether the wrapped executor reaches a broker.
Definition journal.hpp:698
SendOutcome place(const strategy::PlannedOrder &order, std::optional< Decimal64 > baseline)
Records and places one order, stating the holding it was decided against (a serialized Runner calls t...
Definition journal.hpp:770
auto requested_route(Venue asked) const noexcept -> decltype(std::declval< const Executor & >().requested_route(asked))
Returns the wrapped executor's route for a requested venue.
Definition journal.hpp:911
auto last_error() const noexcept -> decltype(std::declval< const Executor & >().last_error())
Returns why the last instruction failed, from the wrapped executor.
Definition journal.hpp:932
const Inner & inner() const noexcept
Returns the wrapped executor.
Definition journal.hpp:872
bool record(JournalEntry &entry)
Appends a line the caller built, such as a serialized Runner's CONFIRMED line.
Definition journal.hpp:823
JournalingExecutor(Inner inner, Journal &journal, Clock clock={})
Wraps an executor.
Definition journal.hpp:706
void clear() noexcept
Forgets every line.
Definition journal.hpp:664
bool append(const JournalEntry &entry)
Appends a line.
Definition journal.hpp:639
MemoryJournal()=default
Constructs a journal with an empty scope.
const std::vector< JournalEntry > & records() const noexcept
Returns the lines recorded.
Definition journal.hpp:661
JournalReplay replay() const
Returns everything recorded.
Definition journal.hpp:651
const std::string & scope() const noexcept
Returns the journal's broker and account.
Definition journal.hpp:670
MemoryJournal(std::string scope)
Constructs a journal.
Definition journal.hpp:632
Runs a strategy: the runner, the polling loop, the order journal, and stopping.
Definition clock.hpp:7
constexpr bool journal_outcome_answers_send(JournalOutcome outcome) noexcept
Tests whether a line with this outcome answers the send itself (the broker's reply,...
Definition journal.hpp:234
std::optional< JournalOutcome > journal_outcome_from(std::string_view text) noexcept
Parses an outcome's name.
Definition journal.hpp:178
constexpr bool journal_outcome_is_closing_account(JournalOutcome outcome) noexcept
Tests whether a line with this outcome is a serialized runner's closing account of a placement (it co...
Definition journal.hpp:295
constexpr std::string_view journal_outcome_name(JournalOutcome outcome) noexcept
Returns an outcome's name as written to the journal ("pending", ...).
Definition journal.hpp:148
JournalReadStatus
Whether a journal file could be read.
Definition journal.hpp:433
@ MISSING
No such file: a first start, nothing owed.
Definition journal.hpp:435
@ READ
The file was read in full.
Definition journal.hpp:437
@ UNREADABLE
The file exists and could not be read; its contents are unknown.
Definition journal.hpp:439
constexpr JournalOutcome journal_outcome_of(SendOutcome outcome) noexcept
Maps a send outcome to the journal outcome that records it.
Definition journal.hpp:190
constexpr std::array< JournalOutcome, 7 > all_journal_outcomes
Every JournalOutcome, in declaration order.
Definition journal.hpp:133
constexpr bool journal_action_matches_by_order_id(JournalAction action) noexcept
Tests whether recovery matches an instruction of this action by the broker's order id it names,...
Definition journal.hpp:67
constexpr bool journal_outcome_refuses(JournalOutcome outcome) noexcept
Tests whether a line with this outcome says the instruction was refused, so it does not exist.
Definition journal.hpp:274
constexpr std::string_view journal_action_name(JournalAction action) noexcept
Returns an action's name as written to the journal ("place", "cancel").
Definition journal.hpp:45
SendOutcome
What became of one instruction (a placement or a cancellation) an executor was asked to send.
Definition execution.hpp:30
@ UNAVAILABLE
Local machinery failed (such as the order journal not being writable), so nothing was sent.
Definition execution.hpp:55
@ INDETERMINATE
The outcome is unknown (see outcome_of): the request failed in transit or was cancelled,...
Definition execution.hpp:48
@ REJECTED
The broker refused the instruction (for a placement, the order does not exist); nothing needs reconci...
Definition execution.hpp:34
@ ACCEPTED
The broker accepted the instruction (for a placement, the order exists).
Definition execution.hpp:32
@ REFUSED_LOCALLY
The binding refused the instruction before sending it (such as an idempotency key at a broker without...
Definition execution.hpp:63
constexpr std::string_view journal_read_status_name(JournalReadStatus status) noexcept
Returns a status's lowercase name, such as "unreadable".
Definition journal.hpp:447
constexpr bool journal_outcome_leaves_open(JournalOutcome outcome) noexcept
Tests whether a line with this outcome leaves its instruction's fate unknown, so recovery must still ...
Definition journal.hpp:338
JournalOutcome
What a journal line says about an instruction.
Definition journal.hpp:93
@ CONFIRMED
A serialized runner accounted for the placement: holdings showed what it filled, its history showed i...
Definition journal.hpp:124
@ INDETERMINATE
The outcome is unknown (SendOutcome::INDETERMINATE: a failure in transit, an unreadable reply,...
Definition journal.hpp:108
@ RESOLVED
A recovery sweep read the broker's order list and closed the question.
Definition journal.hpp:116
@ REJECTED
The instruction was refused, by the broker or before it was sent, so it does not exist.
Definition journal.hpp:103
@ ACCEPTED
The broker accepted the instruction; it exists.
Definition journal.hpp:97
@ HELD
Evidence contradicted the placement (holdings moved past what it can explain), so only an operator ma...
Definition journal.hpp:129
@ PENDING
Written before the send; whether the instruction exists is not yet known.
Definition journal.hpp:95
constexpr std::array< JournalAction, 2 > all_journal_actions
Every JournalAction, in declaration order.
Definition journal.hpp:38
constexpr bool journal_outcome_requires_operator(JournalOutcome outcome) noexcept
Tests whether a line with this outcome is written with requires_operator_ by design,...
Definition journal.hpp:316
std::vector< OpenInstruction > placements_of(const JournalReplay &replay, const std::vector< std::string > &ids)
Returns the placements with the given journal ids, each with the span in which it may have reached th...
Definition journal.hpp:592
std::vector< OpenInstruction > unresolved_instructions(const JournalReplay &replay)
Lists the instructions whose outcome is unknown, in the order they were opened.
Definition journal.hpp:537
JournalAction
Which kind of instruction a journal line records.
Definition journal.hpp:30
@ CANCEL
A cancellation of a resting order.
Definition journal.hpp:34
std::optional< JournalAction > journal_action_from(std::string_view text) noexcept
Parses an action's name.
Definition journal.hpp:82
constexpr bool journal_outcome_names_order(JournalOutcome outcome) noexcept
Tests whether a line with this outcome may carry the broker's id for the order.
Definition journal.hpp:254
constexpr bool journal_outcome_is_terminal(JournalOutcome outcome) noexcept
Tests whether an outcome answers a PENDING line.
Definition journal.hpp:213
The library: broker-neutral types (core), and the modules below.
constexpr std::optional< Enum > value_named(const std::array< Enum, N > &values, Name name, std::string_view text) noexcept
Returns the value of a list whose name is text, so a parser reads exactly what its writer writes.
constexpr bool lists_every_value(const std::array< Enum, N > &values, IsEnumerator is_enumerator) noexcept
Tests whether a list holds every value of an enum exactly once, in any order.
OrderType
How an order's price is decided (its price basis).
Definition types.hpp:1707
@ LIMIT
지정가: fills at the stated price or better.
Definition types.hpp:1710
@ UNREADABLE
No readable date rules it out, but an unreadable date might.
OrderSession
The trading session an order is submitted into.
Definition types.hpp:1839
@ REGULAR
The continuous regular session.
Definition types.hpp:1842
Venue
A trading venue: an exchange, or the combined view across exchanges.
Definition types.hpp:43
TimeInForce
How long an order stays valid and what happens to an unfilled remainder.
Definition types.hpp:1797
@ DAY
Rests until the session ends; an unfilled remainder is cancelled then.
Definition types.hpp:1800
OrderSide
The side of an order: its economic direction, buy or sell.
Definition types.hpp:1683
Reconciliation: turning a strategy's intents and targets into the orders and cancellations to send.
Identifies an instrument: its country, venue and symbol.
Definition types.hpp:78
OrderSide side_
Buy or sell.
Definition types.hpp:2016
OrderType type_
The price basis; UNKNOWN if the broker's code was not recognized.
Definition types.hpp:2018
std::optional< Decimal64 > trigger_price_
The trigger price, whenever the broker reports a positive one.
Definition types.hpp:2048
Decimal64 quantity_
The quantity ordered; the remainder is this minus execution_.filled_quantity_.
Definition types.hpp:2050
InstrumentId instrument_
The instrument (identity venue; the routing venue is venue_).
Definition types.hpp:2012
std::optional< Decimal64 > price_
The limit price, if the order has one.
Definition types.hpp:2040
An order still open to modification or cancellation.
Definition types.hpp:2290
OrderRef< Broker > ref_
The reference to amend or cancel the order with.
Definition types.hpp:2294
OrderSnapshot order_
The order's state.
Definition types.hpp:2292
One journal line: an instruction and what was known about it when the line was written.
Definition journal.hpp:360
std::string id_
Links an answering line to its PENDING line.
Definition journal.hpp:366
std::chrono::system_clock::time_point recorded_at_
When the line was written (for PENDING, before the request went out).
Definition journal.hpp:372
OrderType type_
The order type; recovery matches on type, time in force and session together.
Definition journal.hpp:378
Decimal64 quantity_
The quantity, which recovery matches against.
Definition journal.hpp:392
std::optional< Decimal64 > price_
The price, if the order has one.
Definition journal.hpp:394
JournalOutcome outcome_
What the line says about the instruction.
Definition journal.hpp:370
std::string detail_
Why an answering line says what it says, for the operator.
Definition journal.hpp:410
std::optional< Venue > venue_
The venue the order actually goes to, as the binding resolves it.
Definition journal.hpp:390
InstrumentId instrument_
The instrument (identity; the routing venue is venue_).
Definition journal.hpp:374
std::optional< Decimal64 > trigger_price_
The trigger price of a stop-limit order; empty otherwise (and on lines that predate it).
Definition journal.hpp:396
std::optional< Decimal64 > baseline_
On a serialized runner's placement, the instrument's net holding the order was decided against; on a ...
Definition journal.hpp:403
bool requires_operator_
Whether only an operator may resolve this instruction.
Definition journal.hpp:417
std::string scope_
The broker and account the instruction belongs to, such as "kis:live:12345678-01".
Definition journal.hpp:424
JournalAction action_
Whether the instruction is a placement or a cancellation.
Definition journal.hpp:368
OrderSession session_
The session.
Definition journal.hpp:382
TimeInForce time_in_force_
The time in force.
Definition journal.hpp:380
std::string order_id_
The broker's order id, if known: from the start on a CANCEL line, and only on an answering line for a...
Definition journal.hpp:408
The contents of a journal, including what could not be read.
Definition journal.hpp:464
bool readable() const noexcept
Tests whether the file could be read.
Definition journal.hpp:484
std::size_t unreadable_lines_
How many lines did not parse (on an append-only file, writes that did not finish).
Definition journal.hpp:468
bool intact() const noexcept
Tests whether everything was read.
Definition journal.hpp:499
bool has_header_
Whether a header was found; a non-empty file without one is not written to.
Definition journal.hpp:476
std::string scope_
The broker and account the file's header declares, if it has one.
Definition journal.hpp:474
std::vector< JournalEntry > entries_
Every line that parsed, in file order.
Definition journal.hpp:466
JournalReadStatus status_
Whether the file was read; READ for an in-memory journal.
Definition journal.hpp:478
std::string detail_
What was wrong, for the operator.
Definition journal.hpp:472
bool truncated_tail_
Whether the last line was incomplete, as after a kill during a write.
Definition journal.hpp:470
One instruction of unknown outcome, and the span in which it may have reached the broker.
Definition journal.hpp:510
JournalEntry entry_
The instruction, as its first line recorded it (its order_id_ may come from a later line).
Definition journal.hpp:512
std::string detail_
What the journal says went wrong.
Definition journal.hpp:523
bool answered_
Whether an INDETERMINATE line answered it.
Definition journal.hpp:521
std::optional< std::chrono::system_clock::time_point > closed_at_
When the send was answered: by an INDETERMINATE line in unresolved_instructions, by any answer in rec...
Definition journal.hpp:519
std::chrono::system_clock::time_point opened_at_
When the send began.
Definition journal.hpp:514
One order the runner is to place.
TimeInForce time_in_force_
How long the order stays valid.
OrderSession session_
The trading session.
Venue venue_
Where to route the order; see OrderRequest::venue_.
std::optional< Decimal64 > trigger_price_
The trigger price of a STOP_LIMIT order, exactly as stated; empty otherwise.
OrderType type_
The order type.
InstrumentId instrument_
The instrument to trade.
std::optional< Decimal64 > price_
The limit price, after clamping and rounding; empty for a market order.
Decimal64 quantity_
The quantity, after rounding onto the lot.