algotradelib 0.0.0.9000
C++ header-only library for algorithmic trading
Loading...
Searching...
No Matches
context.hpp
1#pragma once
2
5#include "../strategy/portfolio.hpp"
6
7#include <algotradelib/core>
8
9#if defined(ATL_HAS_EIGEN)
10#include <algotradelib/analytics>
11#endif
12
13#include <chrono>
14#include <cstddef>
15#include <map>
16#include <optional>
17#include <string>
18#include <unordered_map>
19#include <utility>
20#include <variant>
21#include <vector>
22
23namespace algotradelib {
24namespace runner {
25
26// The strategy types a runner speaks in, imported from `strategy`.
27using strategy::BarEvent;
28using strategy::CancelIntent;
29using strategy::Fill;
31using strategy::OrderIntent;
32using strategy::Portfolio;
33using strategy::QuoteEvent;
34using strategy::TargetPosition;
35
44template <typename Broker>
45using Instruction = std::variant<OrderIntent, TargetPosition, CancelIntent<Broker>>;
46
48struct SeriesKey {
52 BarInterval interval_{BarInterval::ONE_DAY};
53
60 friend bool operator<(const SeriesKey& lhs, const SeriesKey& rhs) {
61 if (!(lhs.instrument_ == rhs.instrument_)) {
62 return lhs.instrument_ < rhs.instrument_;
63 }
64 return lhs.interval_ < rhs.interval_;
65 }
66};
67
80template <typename BrokerTag, typename CapsType>
81class Context {
82public:
84 using Broker = BrokerTag;
86 using caps = CapsType;
87
89 Context(const Context&) = delete;
94 Context& operator=(const Context&) = delete;
96 Context(Context&&) = default;
101 Context& operator=(Context&&) = default;
102
104 class Log {
105 public:
110 void note(std::string_view message) {
111 if (lines_.size() >= capacity_) {
112 lines_.erase(lines_.begin());
113 }
114 lines_.emplace_back(message);
115 }
116
121 const std::vector<std::string>& lines() const noexcept { return lines_; }
122
127 std::vector<std::string> take() {
128 std::vector<std::string> taken;
129 taken.swap(lines_);
130 return taken;
131 }
132
133 private:
134 // Bounded so a long session cannot grow it without limit.
135 static constexpr std::size_t capacity_ = 4096;
136 std::vector<std::string> lines_;
137 };
138
144 explicit Context(std::size_t series_capacity = 512) : series_capacity_(series_capacity) {}
145
146 // --- What a strategy reads -------------------------------------------------------------
147
152 std::chrono::system_clock::time_point now() const noexcept { return now_; }
153
158 MarketPhase phase() const noexcept { return phase_; }
159
164 const TradingCalendar& calendar() const noexcept { return calendar_; }
165
170 const Portfolio<BrokerTag>& portfolio() const noexcept { return portfolio_; }
171
177 std::optional<Instrument> instrument(const InstrumentId& id) const {
178 const auto found = instruments_.find(id);
179 if (found == instruments_.end()) {
180 return std::nullopt;
181 }
182 return found->second;
183 }
184
190 std::optional<Decimal64> last_price(const InstrumentId& id) const {
191 const auto found = prices_.find(id);
192 if (found == prices_.end()) {
193 return std::nullopt;
194 }
195 return found->second;
196 }
197
198#if defined(ATL_HAS_EIGEN)
210 const analytics::SeriesBuffer* bars(
211 const InstrumentId& id,
212 BarInterval interval = BarInterval::ONE_DAY
213 ) const {
214 const auto found = series_.find(SeriesKey{id, interval});
215 if (found == series_.end()) {
216 return nullptr;
217 }
218 return &found->second;
219 }
220#endif
221
226 Log& log() noexcept { return log_; }
227
228 // --- What a strategy asks for ---------------------------------------------------------
229
234 void submit(OrderIntent intent) { queued_.emplace_back(std::move(intent)); }
235
240 void submit(TargetPosition target) { queued_.emplace_back(std::move(target)); }
241
247 void cancel(const OrderRef<BrokerTag>& ref, std::string tag = {}) {
248 queued_.emplace_back(CancelIntent<BrokerTag>{ref, std::move(tag)});
249 }
250
251 // --- What the runner uses ------------------------------------------------------------
252
257 const std::vector<Instruction<BrokerTag>>& queued() const noexcept { return queued_; }
258
263 std::vector<Instruction<BrokerTag>> drain() {
264 std::vector<Instruction<BrokerTag>> taken;
265 taken.swap(queued_);
266 return taken;
267 }
268
273 void set_now(std::chrono::system_clock::time_point when) noexcept { now_ = when; }
274
279 void set_phase(MarketPhase phase) noexcept { phase_ = phase; }
280
290 void set_calendar(TradingCalendar calendar) { calendar_ = std::move(calendar); }
291
296 void set_portfolio(Portfolio<BrokerTag> portfolio) { portfolio_ = std::move(portfolio); }
297
302 void set_instrument(Instrument reference) {
303 auto key = reference.id_;
304 instruments_.insert_or_assign(std::move(key), std::move(reference));
305 }
306
312 void set_last_price(const InstrumentId& id, Decimal64 price) {
313 prices_.insert_or_assign(id, std::move(price));
314 }
315
316#if defined(ATL_HAS_EIGEN)
323 void record_bar(const BarEvent& event) {
324 const SeriesKey key{event.instrument_, event.interval_};
325 auto found = series_.find(key);
326 if (found == series_.end()) {
327 found = series_.emplace(key, analytics::SeriesBuffer(series_capacity_)).first;
328 }
329 found->second.push(event.bar_);
330 }
331#endif
332
333private:
334 // Hashes an instrument id for the two per-instrument tables below. Both are looked up by id and
335 // never iterated, so their order is nobody's to observe.
336 struct InstrumentHash {
337 std::size_t operator()(const InstrumentId& id) const noexcept {
338 std::size_t seed = std::hash<std::string>{}(id.symbol_);
339 seed ^= static_cast<std::size_t>(id.country_) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);
340 seed ^= static_cast<std::size_t>(id.venue_) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);
341 return seed;
342 }
343 };
344
345 std::size_t series_capacity_;
346 std::chrono::system_clock::time_point now_{};
347 MarketPhase phase_{MarketPhase::UNKNOWN};
348 TradingCalendar calendar_;
349 Portfolio<BrokerTag> portfolio_;
350 std::unordered_map<InstrumentId, Instrument, InstrumentHash> instruments_;
351 std::unordered_map<InstrumentId, Decimal64, InstrumentHash> prices_;
352#if defined(ATL_HAS_EIGEN)
353 std::map<SeriesKey, analytics::SeriesBuffer> series_;
354#endif
355 std::vector<Instruction<BrokerTag>> queued_;
356 Log log_;
357};
358
359} // namespace runner
360} // namespace algotradelib
An exact signed decimal: an int64 coefficient times 10^-scale.
Definition types.hpp:297
The most recent observations of a few fields, for a strategy fed one bar at a time.
A log that keeps lines in memory for the runner to emit or a test to read.
Definition context.hpp:104
std::vector< std::string > take()
Removes and returns the recorded lines.
Definition context.hpp:127
void note(std::string_view message)
Records one line; when 4096 lines are held, the oldest is dropped.
Definition context.hpp:110
const std::vector< std::string > & lines() const noexcept
Returns the lines recorded since the last take.
Definition context.hpp:121
Context(Context &&)=default
Move constructor: takes the state of the context passed in, which is left valid but unspecified.
void set_phase(MarketPhase phase) noexcept
Sets the market phase (for runners).
Definition context.hpp:279
std::optional< Decimal64 > last_price(const InstrumentId &id) const
Returns the latest price seen for an instrument (a quote's last price or a bar's close).
Definition context.hpp:190
std::chrono::system_clock::time_point now() const noexcept
Returns the instant the runner is acting at.
Definition context.hpp:152
const TradingCalendar & calendar() const noexcept
Returns the trading calendar the runner last read.
Definition context.hpp:164
std::optional< Instrument > instrument(const InstrumentId &id) const
Returns an instrument's reference data, including its price grid.
Definition context.hpp:177
Log & log() noexcept
Returns the log.
Definition context.hpp:226
Context & operator=(const Context &)=delete
Deleted: a context cannot be copied.
void submit(TargetPosition target)
Queues a target position; the runner trades the difference from the portfolio.
Definition context.hpp:240
const std::vector< Instruction< BrokerTag > > & queued() const noexcept
Returns the queued requests without removing them (for runners).
Definition context.hpp:257
void set_portfolio(Portfolio< BrokerTag > portfolio)
Replaces the portfolio (for runners).
Definition context.hpp:296
Context(const Context &)=delete
Deleted: a context cannot be copied, so a handler cannot take it by value.
CapsType caps
The broker capabilities, for if constexpr (Ctx::caps::has_depth) and the like.
Definition context.hpp:86
MarketPhase phase() const noexcept
Returns the market phase.
Definition context.hpp:158
void cancel(const OrderRef< BrokerTag > &ref, std::string tag={})
Queues a cancellation of a working order.
Definition context.hpp:247
Context & operator=(Context &&)=default
Move assignment: takes the other context's state.
void set_now(std::chrono::system_clock::time_point when) noexcept
Sets the current instant (for runners).
Definition context.hpp:273
void set_calendar(TradingCalendar calendar)
Replaces the trading calendar (for runners and sources, not strategies).
Definition context.hpp:290
std::vector< Instruction< BrokerTag > > drain()
Removes and returns the queued requests (for runners).
Definition context.hpp:263
BrokerTag Broker
The broker tag of the order references.
Definition context.hpp:84
const Portfolio< BrokerTag > & portfolio() const noexcept
Returns the portfolio: positions, buying power and the orders still working.
Definition context.hpp:170
void submit(OrderIntent intent)
Queues an order; the runner checks and sends it after the handler returns.
Definition context.hpp:234
Context(std::size_t series_capacity=512)
Constructs a context.
Definition context.hpp:144
void set_instrument(Instrument reference)
Adds or replaces an instrument's reference data.
Definition context.hpp:302
void set_last_price(const InstrumentId &id, Decimal64 price)
Records an instrument's latest price, used to value market orders and size notionals.
Definition context.hpp:312
One order a strategy asks the runner to place.
Definition intent.hpp:249
The events a runner delivers to a strategy's handlers, and the market phase.
What a strategy asks the runner for: orders (OrderIntent), target positions (TargetPosition) and canc...
Runs a strategy: the runner, the polling loop, the order journal, and stopping.
Definition clock.hpp:7
std::variant< OrderIntent, TargetPosition, CancelIntent< Broker > > Instruction
One request a strategy queued: an order, a target position or a cancellation.
Definition context.hpp:45
MarketPhase
Where the clock stands relative to the trading session.
Definition event.hpp:30
The library: broker-neutral types (core), and the modules below.
BarInterval
The period one bar covers.
Identifies an instrument: its country, venue and symbol.
Definition types.hpp:78
Reference data for one instrument.
InstrumentId id_
The instrument.
A broker's reference to one order, used to amend or cancel it.
Definition types.hpp:2111
The trading days a broker reported for one market, ascending by date.
Definition calendar.hpp:44
Identifies one cached bar series: an instrument at one bar interval.
Definition context.hpp:48
InstrumentId instrument_
The instrument.
Definition context.hpp:50
friend bool operator<(const SeriesKey &lhs, const SeriesKey &rhs)
Orders keys by instrument, then interval, so they can key a map.
Definition context.hpp:60
BarInterval interval_
The bar interval; one instrument at two intervals is two series.
Definition context.hpp:52
One bar, delivered to on_bar.
Definition event.hpp:202
A request to cancel one working order.
Definition intent.hpp:471
What the account holds and which orders are still working, as a strategy sees it.
Definition portfolio.hpp:50
The position a strategy wants to hold in one instrument.
Definition intent.hpp:442