14#include <algotradelib/runner>
35using Clock = std::chrono::system_clock;
37InstrumentId samsung() {
return InstrumentId{Country::KR, Venue::COMBINED,
"005930"}; }
40Clock::time_point sent_at() {
return Clock::time_point{} + std::chrono::hours(24 * 20000); }
45 order.
side_ = OrderSide::BUY;
46 order.
type_ = OrderType::LIMIT;
48 order.
price_ = Decimal64::parse(
"70000");
60template <
typename Tag>
64 throw std::runtime_error(
"the process died with the request on the wire");
72void show_journal(
const std::string& path) {
73 std::FILE* handle = std::fopen(path.c_str(),
"rb");
74 if (handle ==
nullptr) {
75 std::cout <<
" (no journal)\n";
80 while (
const auto read = std::fread(buffer, 1,
sizeof(buffer), handle)) {
81 text.append(buffer, read);
85 std::size_t begin = 0;
86 while (begin < text.size()) {
87 const auto end = text.find(
'\n', begin);
88 const auto stop = end == std::string::npos ? text.size() : end;
89 std::cout <<
" " << text.substr(begin, stop - begin);
90 if (end == std::string::npos) {
91 std::cout <<
" <- no newline: this write never finished";
94 if (end == std::string::npos) {
102OrderSnapshot listed_order() {
103 OrderSnapshot snapshot;
104 snapshot.order_id_ =
"KRX-4412";
105 snapshot.instrument_ = samsung();
106 snapshot.side_ = OrderSide::BUY;
107 snapshot.type_ = OrderType::LIMIT;
108 snapshot.status_ = OrderStatus::PENDING;
109 snapshot.quantity_ = Decimal64::parse(
"10");
110 snapshot.price_ = Decimal64::parse(
"70000");
111 snapshot.ordered_at_ = sent_at();
118 const std::string path =
"example-order-journal.jsonl";
119 std::remove(path.c_str());
121 std::cout <<
"1. A runner sends one order, and is killed before it learns the outcome.\n\n";
124 if (!journal.open()) {
125 std::cout <<
"could not open " << path <<
" for appending: " << journal.rejection() <<
"\n";
133 executor.
place(buy_ten());
134 }
catch (
const std::exception& error) {
135 std::cout <<
" " << error.what() <<
"\n\n";
139 std::cout <<
" What the file holds:\n";
142 <<
"\n One line, and it says `pending`. The order may be resting on the exchange or may\n"
143 <<
" never have arrived. Nothing in this process knows which, and the process is gone.\n\n";
145 std::cout <<
"2. A new process starts. Its ledger is empty.\n\n";
147 std::cout <<
" Before recovery, may it trade " << samsung().symbol_
149 <<
" <- and that is the trap\n";
152 std::cout <<
" After recovery: "
154 std::cout <<
" Instruments marked: " << recovery.marked_.size()
155 <<
", instructions owed: " << recovery.open_.size() <<
"\n\n";
157 std::cout <<
"3. The broker's own order list is read, and it is the only thing that resolves.\n\n";
163 recovery.open_, {}, sent_at() + std::chrono::seconds(5), ledger, journal
165 std::cout <<
" Five seconds later, an empty listing: "
167 <<
" -- still withheld\n";
171 recovery.open_, {listed_order()}, sent_at() + std::chrono::minutes(10), ledger, journal
173 std::cout <<
" Ten minutes later, the order is listed: "
175 << settled.matches_.front().order_id_ <<
"\n";
176 std::cout <<
" May it trade " << samsung().symbol_ <<
" now? "
179 std::cout <<
"4. The resolution is written back, so a second restart finds nothing owed.\n\n";
180 std::cout <<
" What the file holds now:\n";
185 std::cout <<
"\n A third process recovers: instructions owed: " << again.open_.size()
186 <<
", may it trade " << samsung().symbol_ <<
"? "
190 <<
"Had the listing stayed empty past the window, the verdict would have been `not_placed`:\n"
191 <<
"no order found, and the ledger would have cleared just the same. A serialized runner goes\n"
192 <<
"on owing such an order all the same, since a list can lag an order it accepted. Had two\n"
193 <<
"rows matched, it would have been `ambiguous`, nothing would clear, and an operator would\n"
194 <<
"decide. The one thing that never happens is a guess.\n";
196 std::remove(path.c_str());
An exact signed decimal: an int64 coefficient times 10^-scale.
The order journal on disk: one JSON object per line, appended and flushed to disk (fsync) before appe...
The instruments with an order of unknown outcome, where nothing may be placed until the broker's orde...
bool requires_reconcile(const InstrumentId &id) const
Tests whether an instrument is waiting for reconciliation.
An executor wrapper that records each instruction in a journal before sending it.
void set_id_prefix(std::string prefix)
Sets the prefix of line ids.
SendOutcome place(const strategy::PlannedOrder &order)
Records and places one order.
A clock for tests: wait_for advances it instead of sleeping.
Runs a strategy: the runner, the polling loop, the order journal, and stopping.
JournalReplay read_journal_file(const std::string &path)
Reads and parses a journal file.
SendOutcome
What became of one instruction (a placement or a cancellation) an executor was asked to send.
@ ACCEPTED
The broker accepted the instruction (for a placement, the order exists).
RecoveryReport recover_into(const JournalReplay &replay, IndeterminacyLedger &ledger)
Marks the ledger for every instrument a journal left an instruction of unknown outcome for.
ReconcileReport reconcile_against(const std::vector< OpenInstruction > &open, const std::vector< OrderSnapshot > &rows, const JournalReplay &replay, std::chrono::system_clock::time_point now, IndeterminacyLedger &ledger, Journal &journal, const MatchWindow &window={}, std::string_view unplaced_note={})
Resolves what a broker listing settles, records it in the journal, and clears the ledger for each ins...
constexpr std::string_view match_verdict_name(MatchVerdict verdict) noexcept
Returns a verdict's lowercase name, such as "not_placed", for logs.
void stop(S &strategy, Ctx &context)
Calls strategy.on_stop(context) if the strategy declares on_stop; otherwise does nothing.
What a strategy sees and emits: events, intents, the portfolio, reconciliation and risk limits.
OrderStatus
Where an order stands in its lifecycle.
OrderType
How an order's price is decided (its price basis).
Country
A country (market) the library supports.
Venue
A trading venue: an exchange, or the combined view across exchanges.
OrderSide
The side of an order: its economic direction, buy or sell.
Identifies an instrument: its country, venue and symbol.
The state of one order, as a broker listing reported it.
One order the runner is to place.
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.