18#include <algotradelib/kis>
19#include <algotradelib/tossinvest>
21#include <boost/asio/ssl/context.hpp>
32namespace ssl = boost::asio::ssl;
37using algotradelib::BarQuery;
38using algotradelib::BarSeries;
39using algotradelib::BlockingSession;
40using algotradelib::BrokerCaps;
41using algotradelib::BrokerError;
43using algotradelib::DepthSnapshot;
44using algotradelib::Instrument;
45using algotradelib::InstrumentId;
47using algotradelib::PriceLimits;
48using algotradelib::StatedDate;
49using algotradelib::TradingCalendar;
54void print_error(std::string_view operation,
const BrokerError& error) {
55 std::cerr <<
" " << operation <<
" failed";
56 if (!error.broker_code_.empty()) {
57 std::cerr <<
" [" << error.broker_code_ <<
']';
59 if (!error.message_.empty()) {
60 std::cerr <<
": " << error.message_;
66void print_bars(
const BarSeries& series) {
67 std::cout <<
"bars: " << series.bars_.size() <<
' '
68 <<
bar_interval_name(series.interval_) << (series.adjusted_ ?
" adjusted" :
" raw")
69 <<
' ' << series.currency_.str() <<
", stamped at each period's "
71 if (series.bars_.empty()) {
74 std::cout <<
" ascending: " << (series.ascending() ?
"yes" :
"no") <<
'\n';
75 for (
const auto* bar : {&series.bars_.front(), &series.bars_.back()}) {
76 std::cout <<
" " << (
bar == &series.bars_.front() ?
"oldest" :
"newest")
77 <<
" close=" <<
bar->close_.str() <<
" volume=" <<
bar->volume_.str()
78 <<
" open=" << (
bar->open_ ?
bar->open_->str() : std::string(
"not reported")) <<
'\n';
80 if (series.next_cursor_) {
81 std::cout <<
" may continue from " << *series.next_cursor_ <<
'\n';
86void print_depth(
const DepthSnapshot& book) {
87 std::cout <<
"book: " << book.bids_.size() <<
" bids, " << book.asks_.size() <<
" asks\n";
88 const auto bid = book.best_bid();
89 const auto ask = book.best_ask();
90 std::cout <<
" best bid: " << (bid ? bid->price_.str() : std::string(
"none"))
91 <<
" best ask: " << (ask ? ask->price_.str() : std::string(
"none")) <<
'\n';
92 const auto spread = book.spread();
93 const auto mid = book.mid();
94 std::cout <<
" spread: " << (spread ? spread->str() : std::string(
"not both sides"))
95 <<
" mid: " << (mid ? mid->str() : std::string(
"not both sides")) <<
'\n';
99void print_price_limits(
const PriceLimits& limits) {
100 std::cout <<
"price bounds: "
101 << (limits.lower_ ? limits.lower_->str() : std::string(
"no lower limit")) <<
" .. "
102 << (limits.upper_ ? limits.upper_->str() : std::string(
"no upper limit")) <<
' '
103 << limits.currency_.str() <<
'\n';
107void print_instrument(
const Instrument& instrument) {
108 std::cout <<
"instrument: " << instrument.name_;
109 if (!instrument.english_name_.empty()) {
110 std::cout <<
" (" << instrument.english_name_ <<
')';
112 std::cout <<
"\n market: " << instrument.segment_.str();
113 if (!instrument.isin_.empty()) {
114 std::cout <<
" isin: " << instrument.isin_;
116 switch (instrument.listed_on_.state()) {
117 case StatedDate::State::STATED: {
118 const auto& listed = instrument.listed_on_.date();
119 std::cout <<
" listed: " << listed.year_ <<
'-' << listed.month_ <<
'-' << listed.day_;
122 case StatedDate::State::UNREADABLE:
124 std::cout <<
" listed: (unreadable)";
126 case StatedDate::State::NOT_STATED:
130 std::cout <<
" price grid: " << instrument.price_rule_.source_ <<
'\n';
134void print_calendar(
const TradingCalendar& calendar) {
135 std::cout <<
"calendar: " << calendar.days_.size() <<
" date(s) covered\n";
136 for (
const auto& day : calendar.days_) {
137 std::cout <<
" " << day.date_.year_ <<
'-' << day.date_.month_ <<
'-' << day.date_.day_
138 << (day.open_ ?
" market opens" :
" market closed") <<
'\n';
148template <
typename Client>
149int report(BlockingSession<Client>& session,
const InstrumentId& subject) {
150 using Caps = BrokerCaps<Client>;
152 std::cout <<
"broker: " << session.broker_name() <<
"\n\n";
154 algotradelib::PriceRule reference_rule;
155 if (
auto reference = session.instrument(subject)) {
156 print_instrument(reference.value());
157 reference_rule = reference.value().price_rule_;
159 print_error(
"reference data", reference.error());
163 daily.instrument_ = subject;
164 daily.interval_ = BarInterval::ONE_DAY;
166 if (
auto bars = session.bars(daily)) {
167 print_bars(
bars.value());
169 print_error(
"daily bars",
bars.error());
172 if constexpr (Caps::supports_interval(BarInterval::ONE_WEEK)) {
175 BarQuery weekly = daily;
176 weekly.interval_ = BarInterval::ONE_WEEK;
178 if (
auto bars = session.bars(weekly)) {
179 print_bars(
bars.value());
181 print_error(
"weekly bars",
bars.error());
184 std::cout <<
"bars: this broker publishes no period longer than a day\n";
187 if constexpr (Caps::has_depth) {
188 if (
auto book = session.depth(subject)) {
189 print_depth(book.value());
193 if (
const auto mid = book.value().mid()) {
197 const auto rule = reference_rule;
199 std::cout <<
" a buy at the midpoint would rest at "
200 << (buy ? buy->str() : std::string(
"no grid known for this instrument")) <<
'\n';
203 print_error(
"order book", book.error());
207 if constexpr (Caps::has_price_limits) {
208 if (
auto limits = session.price_limits(subject)) {
209 print_price_limits(limits.value());
211 print_error(
"price bounds", limits.error());
215 if constexpr (Caps::has_trade_prints) {
216 if (
auto prints = session.trades(subject, 5)) {
217 std::cout <<
"recent executions: " << prints.value().size() <<
'\n';
218 for (
const auto& print : prints.value()) {
219 std::cout <<
" " << print.price_.str() <<
" x " << print.quantity_.str() <<
'\n';
222 print_error(
"recent executions", prints.error());
226 if constexpr (Caps::has_batch_prices) {
229 if (
auto quotes = session.prices({subject})) {
230 std::cout <<
"batch quotes: " << quotes.value().size() <<
'\n';
232 print_error(
"batch quotes", quotes.error());
235 std::cout <<
"batch quotes: this broker quotes one instrument per request\n";
238 if constexpr (Caps::has_calendar) {
239 if (
auto calendar = session.calendar(subject.country_)) {
240 print_calendar(calendar.value());
241 if constexpr (!Caps::has_calendar_range) {
242 std::cout <<
" one request covers the requested day and the ones either side\n";
245 print_error(
"calendar", calendar.error());
249 if constexpr (Caps::has_calendar_sessions) {
250 std::cout <<
"sessions: this broker publishes intraday session windows; the library "
251 <<
"does not expose them yet\n";
258int report_kis(ssl::context& tls,
const std::string& symbol) {
259 namespace kis = algotradelib::kis;
261 kis::KisConfig config;
262 kis::KisAccount account;
266 std::make_shared<kis::KisBlockingClient>(tls, std::move(config), kis_credentials::paced_options());
267 BlockingSession<kis::KisBlockingClient> session(std::move(client), std::move(account));
268 return report(session, InstrumentId{Country::KR, Venue::COMBINED, symbol});
272int report_tossinvest(ssl::context& tls,
const std::string& symbol,
const char* sequence) {
273 namespace toss = algotradelib::tossinvest;
275 toss::TossConfig config;
277 auto client = std::make_shared<toss::TossBlockingClient>(tls, std::move(config));
279 std::int64_t selected = 0;
281 selected = std::strtoll(sequence,
nullptr, 10);
285 print_error(
"account discovery", accounts.error());
288 if (accounts.value().empty()) {
289 std::cerr <<
"no Toss accounts are available for these credentials\n";
292 selected = accounts.value().front().selector_;
295 BlockingSession<toss::TossBlockingClient> session(std::move(client), selected);
296 return report(session, InstrumentId{Country::KR, Venue::COMBINED, symbol});
301int main(
int argc,
char** argv) {
302 const std::string broker = argc > 1 ? argv[1] :
"";
303 if (broker !=
"kis" && broker !=
"tossinvest") {
305 <<
"usage: example-portable-market-data <kis|tossinvest> [symbol] [account-sequence]\n";
308 const std::string symbol = argc > 2 ? argv[2] :
"005930";
311 ssl::context tls(ssl::context::tls_client);
312 tls.set_default_verify_paths();
313 tls.set_verify_mode(ssl::verify_peer);
315 if (broker ==
"kis") {
316 return report_kis(tls, symbol);
318 return report_tossinvest(tls, symbol, argc > 3 ? argv[3] :
nullptr);
319 }
catch (
const std::exception& exception) {
320 std::cerr <<
"example failed: " << exception.what() <<
'\n';
The examples' KIS credentials: one JSON file per account, or the environment.
void load(const std::optional< std::filesystem::path > &directory, algotradelib::kis::KisConfig &config, algotradelib::kis::KisAccount *account, std::ostream &out)
Loads the credentials (and account) KIS_DEMO chooses, and prints where from (a path or "environment v...
void bar(S &strategy, Ctx &context, const BarEvent &event)
Calls strategy.on_bar(context, event) if the strategy declares on_bar; otherwise does nothing.
void bars(S &strategy, Ctx &context, const BarSlice &slice)
Calls strategy.on_bars(context, slice) if the strategy declares on_bars; otherwise does nothing.
@ OPEN
The timestamp is the first instant of the period.
Result< std::vector< AccountInfo< Client > > > list_accounts(Client &client)
Lists a broker's accounts with a blocking client, before a session exists; requires BrokerCaps<Client...
constexpr std::string_view bar_interval_name(BarInterval interval) noexcept
Returns a short name for an interval, such as "1m", "5m", "1h" or "1d".
Country
A country (market) the library supports.
Venue
A trading venue: an exchange, or the combined view across exchanges.
BarInterval
The period one bar covers.
OrderSide
The side of an order: its economic direction, buy or sell.
std::optional< Decimal64 > round_to_tick(const Decimal64 &price, OrderSide side) const
Rounds a price to its band's tick in the order's favour: a buy rounds down, a sell up.