21#include <algotradelib/kis>
22#include <algotradelib/tossinvest>
24#include <boost/asio/ssl/context.hpp>
34namespace ssl = boost::asio::ssl;
38using algotradelib::BlockingSession;
39using algotradelib::BrokerCaps;
40using algotradelib::BrokerError;
41using algotradelib::HoldingsSnapshot;
44std::string mask_account_number(std::string_view account_number) {
45 if (account_number.size() <= 4) {
46 return std::string(account_number.size(),
'*');
48 return std::string(account_number.size() - 4,
'*') +
49 std::string(account_number.substr(account_number.size() - 4));
53void print_error(std::string_view operation,
const BrokerError& error) {
54 std::cerr << operation <<
" failed";
55 if (!error.broker_code_.empty()) {
56 std::cerr <<
" [" << error.broker_code_ <<
']';
58 if (error.http_status_ != 0) {
59 std::cerr <<
" HTTP " << error.http_status_;
61 if (!error.message_.empty()) {
62 std::cerr <<
": " << error.message_;
64 if (error.retry_after_) {
65 std::cerr <<
" (retry after " << error.retry_after_->count() <<
"s)";
71void print_holdings(
const HoldingsSnapshot& snapshot) {
72 std::cout <<
"positions: " << snapshot.positions_.size() <<
'\n';
73 for (
const auto& position : snapshot.positions_) {
74 std::cout <<
" " << position.instrument_.symbol_ <<
" " << position.name_
75 <<
" quantity=" << position.quantity_.str()
76 <<
" market=" << position.market_value_.amount_.str() <<
' '
77 << position.market_value_.currency_.str() <<
'\n';
79 for (
const auto& total : snapshot.totals_) {
80 std::cout <<
" total " << total.currency_.str()
81 <<
" purchase=" << total.purchase_value_.str()
82 <<
" market=" << total.market_value_.str()
83 <<
" unrealized=" << total.unrealized_profit_loss_.str() <<
'\n';
88template <
typename Broker>
89void print_working_orders(
const algotradelib::WorkingOrders<Broker>& orders) {
90 std::cout <<
"working orders: " << orders.
orders_.size() <<
'\n';
91 for (
const auto& working : orders.
orders_) {
92 std::cout <<
" " << working.order_.instrument_.symbol_
93 <<
" reference=" << working.ref_.str()
94 <<
" ordered=" << working.order_.quantity_.str()
95 <<
" filled=" << working.order_.execution_.filled_quantity_.str();
96 if (working.amendable_quantity_) {
97 std::cout <<
" amendable=" << working.amendable_quantity_->str();
99 std::cout <<
" amendable=not reported";
112template <
typename Client>
113int report(BlockingSession<Client>& session) {
114 using Caps = BrokerCaps<Client>;
116 std::cout <<
"broker: " << session.broker_name() <<
'\n';
117 std::cout <<
"reports an amendable quantity: "
118 << (Caps::has_amendable_quantity ?
"yes" :
"no") <<
'\n';
119 std::cout <<
"accepts an idempotency key: "
120 << (Caps::has_client_order_id ?
"yes" :
"no") <<
'\n';
122 auto holdings = session.holdings();
124 print_error(
"holdings request", holdings.error());
127 print_holdings(holdings.value());
129 if constexpr (Caps::has_working_orders) {
130 auto working = session.working_orders();
135 print_error(
"working-order inquiry", working.error());
137 print_working_orders(working.value());
145int report_kis(ssl::context& tls) {
146 namespace kis = algotradelib::kis;
148 kis::KisConfig config;
149 kis::KisAccount account;
152 std::cout <<
"environment: " << (config.is_demo_ ?
"demo" :
"live") <<
'\n';
155 std::make_shared<kis::KisBlockingClient>(tls, std::move(config), kis_credentials::paced_options());
156 BlockingSession<kis::KisBlockingClient> session(std::move(client), std::move(account));
157 return report(session);
161int report_tossinvest(ssl::context& tls,
const char* requested_sequence) {
162 namespace toss = algotradelib::tossinvest;
164 toss::TossConfig config;
167 auto client = std::make_shared<toss::TossBlockingClient>(tls, std::move(config));
169 std::int64_t sequence = 0;
170 if (requested_sequence) {
171 sequence = std::strtoll(requested_sequence,
nullptr, 10);
175 print_error(
"account discovery", accounts.error());
178 if (accounts.value().empty()) {
179 std::cerr <<
"no Toss accounts are available for these credentials\n";
182 for (
const auto& account : accounts.value()) {
183 std::cout <<
"account " << mask_account_number(account.display_number_) <<
" type=" << account.type_
184 <<
" sequence=" << account.selector_ <<
'\n';
186 sequence = accounts.value().front().selector_;
189 BlockingSession<toss::TossBlockingClient> session(std::move(client), sequence);
190 return report(session);
195int main(
int argc,
char** argv) {
196 const std::string broker = argc > 1 ? argv[1] :
"";
197 if (broker !=
"kis" && broker !=
"tossinvest") {
198 std::cerr <<
"usage: example-portable-holdings <kis|tossinvest> [account-sequence]\n";
203 ssl::context tls(ssl::context::tls_client);
204 tls.set_default_verify_paths();
205 tls.set_verify_mode(ssl::verify_peer);
207 if (broker ==
"kis") {
208 return report_kis(tls);
210 return report_tossinvest(tls, argc > 2 ? argv[2] :
nullptr);
211 }
catch (
const std::exception& exception) {
212 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...
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...
std::vector< WorkingOrder< Broker > > orders_
The open orders.