algotradelib 0.0.0.9000
C++ header-only library for algorithmic trading
Loading...
Searching...
No Matches
config.hpp
1#pragma once
2
3#include "../../network/oauth.hpp"
4
5#include "../../core/types.hpp"
6
7#include <boost/json.hpp>
8
9#include <chrono>
10#include <cstdlib>
11#include <ctime>
12#include <fstream>
13#include <iterator>
14#include <stdexcept>
15#include <string>
16#include <string_view>
17
18namespace algotradelib {
19namespace kiwoom {
20
21// https://openapi.kiwoom.com/guide/apiguide
22// Token issue: au10001 POST https://api.kiwoom.com/oauth2/token
23// Token revoke: au10002 POST https://api.kiwoom.com/oauth2/revoke
24struct KiwoomConfig;
25struct KiwoomRest;
26
33enum class MarketTape {
35 CONSOLIDATED,
37 KRX,
39 NXT,
40};
41
47inline constexpr const char* tape_suffix(MarketTape tape) noexcept {
48 switch (tape) {
49 case MarketTape::KRX:
50 return "";
51 case MarketTape::NXT:
52 return "_NX";
54 return "_AL";
55 }
56 return "_AL";
57}
58
65inline std::chrono::system_clock::time_point parse_compact_expiry(std::string_view text) {
66 if (text.size() != 14) {
67 return {};
68 }
69 for (const char digit : text) {
70 if (digit < '0' || digit > '9') {
71 return {};
72 }
73 }
74 const auto number = [text](std::size_t offset, std::size_t length) {
75 int value = 0;
76 for (std::size_t index = offset; index < offset + length; ++index) {
77 value = value * 10 + (text[index] - '0');
78 }
79 return value;
80 };
81 std::tm parts{};
82 parts.tm_year = number(0, 4) - 1900;
83 parts.tm_mon = number(4, 2) - 1;
84 parts.tm_mday = number(6, 2);
85 parts.tm_hour = number(8, 2);
86 parts.tm_min = number(10, 2);
87 parts.tm_sec = number(12, 2);
88 parts.tm_isdst = 0;
89#ifdef _WIN32
90 const std::time_t utc = _mkgmtime(&parts) - 9 * 3600;
91#else
92 const std::time_t utc = timegm(&parts) - 9 * 3600;
93#endif
94 return std::chrono::system_clock::from_time_t(utc);
95}
96
114
124inline constexpr bool kiwoom_position_scope_asserted(KiwoomPositionScope scope) noexcept {
125 switch (scope) {
127 return false;
129 return true;
130 }
131 return false;
132}
133
144
154struct KiwoomConfig : public network::ClientCredentials<KiwoomConfig> {
162 bool is_demo_ = true;
163
171
182 Venue holdings_venue_ = Venue::UNSPECIFIED;
183
194
203
210 const char* key = std::getenv("KIWOOM_APP_KEY");
211 const char* secret = std::getenv("KIWOOM_SECRET_KEY");
212 if (!key || !secret) {
213 throw std::runtime_error("Add KIWOOM_APP_KEY and KIWOOM_SECRET_KEY environment variables.");
214 }
215 // Read before anything is assigned, so a refused load leaves this config as it was.
216 const bool demo = demo_from_env();
217 key_ = key;
218 secret_ = secret;
219 is_demo_ = demo;
220 }
221
233 void from_json_impl(const std::string& filename) {
234 std::ifstream ifs(filename);
235 if (!ifs.is_open()) {
236 throw std::runtime_error("Cannot open Kiwoom credential file: " + filename);
237 }
238 const std::string content(
239 std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>{}
240 );
241 boost::system::error_code ec;
242 const auto jv = json::parse(content, ec);
243 if (ec || !jv.is_object()) {
244 throw std::runtime_error(
245 "Failed to parse Kiwoom credentials file: " + filename +
246 (ec ? " — " + ec.message() : std::string(" — not a JSON object"))
247 );
248 }
249 const auto& doc = jv.as_object();
250 const json::value* key = doc.if_contains("appkey");
251 const json::value* secret = doc.if_contains("secretkey");
252 if (!key || !secret || !key->is_string() || !secret->is_string()) {
253 throw std::runtime_error("Credential file should contain appkey and secretkey as strings");
254 }
255 // Everything is read and checked before anything is assigned, so a refused file leaves this
256 // config -- and the endpoint it already selected -- exactly as it was.
257 const bool demo = demo_from_json(doc, filename);
258 key_ = key->get_string().c_str();
259 secret_ = secret->get_string().c_str();
260 is_demo_ = demo;
261 }
262
268 static bool demo_from_env() {
269 const char* demo = std::getenv("KIWOOM_DEMO");
270 if (!demo || std::string_view(demo) == "1") {
271 return true;
272 }
273 if (std::string_view(demo) == "0") {
274 return false;
275 }
276 throw std::runtime_error(
277 std::string("KIWOOM_DEMO is \"") + demo + "\"; set it to 1 for the demo endpoints or 0 to trade "
278 "live, or leave it unset for demo."
279 );
280 }
281
289 static bool demo_from_json(const json::object& doc, const std::string& filename) {
290 const json::value* demo = doc.if_contains("demo");
291 if (!demo) {
292 return true;
293 }
294 if (!demo->is_bool()) {
295 throw std::runtime_error(
296 "Kiwoom credential file " + filename + " has a \"demo\" that is not true or false; write "
297 "true for the demo endpoints or false to trade live, or leave it out for demo."
298 );
299 }
300 return demo->get_bool();
301 }
302
307 static constexpr std::string_view key_field() noexcept { return "appkey"; }
308
313 static constexpr std::string_view secret_field() noexcept { return "secretkey"; }
314
319 const char* rest_host() const noexcept {
320 return is_demo_ ? "mockapi.kiwoom.com" : "api.kiwoom.com";
321 }
322
327 const char* rest_port() const noexcept { return "443"; }
328
333 const char* ws_host() const noexcept {
334 return is_demo_ ? "mockapi.kiwoom.com" : "api.kiwoom.com";
335 }
336
341 const char* ws_port() const noexcept { return "10000"; }
342
348 std::string tape_symbol(std::string_view symbol) const {
349 return std::string(symbol) + tape_suffix(market_tape_);
350 }
351};
352
354struct KiwoomRest : public network::AuthBody<KiwoomRest> {
356 std::string token_type_;
357
362 static constexpr std::string_view token_field() noexcept { return "token"; }
363
369 void from_json_impl(const json::object& doc) {
370 if (const auto expiry = doc.if_contains("expires_dt"); expiry && expiry->is_string()) {
371 expires_at_ = parse_compact_expiry(std::string_view(expiry->as_string()));
372 }
373 if (const auto type = doc.if_contains("token_type"); type && type->is_string()) {
374 token_type_ = type->as_string().c_str();
375 }
376 }
377};
378
379} // namespace kiwoom
380} // namespace algotradelib
OAuth client credentials (an app key and secret), the base of each broker's credentials class.
Definition oauth.hpp:36
const std::string & key() const noexcept
Definition oauth.hpp:62
const std::string & secret() const noexcept
Definition oauth.hpp:68
The Kiwoom Securities REST API client.
Definition auth.hpp:12
constexpr const char * tape_suffix(MarketTape tape) noexcept
Returns the symbol suffix for a tape.
Definition config.hpp:47
MarketTape
Which venue's prices Kiwoom market-data requests read (see KiwoomConfig::market_tape_).
Definition config.hpp:33
@ CONSOLIDATED
KRX and NXT combined, the SOR book (_AL).
Definition config.hpp:35
@ KRX
KRX alone (no suffix).
Definition config.hpp:37
KiwoomSellableScope
What a Kiwoom holdings row's tradable quantity (trde_able_qty) covers; undocumented,...
Definition config.hpp:138
@ UNSPECIFIED
Not stated: the sellable basis is unestablished, and a sell checked against it is refused.
Definition config.hpp:140
@ WHOLE_HOLDING
Asserted: it covers every share held of the instrument, on any venue.
Definition config.hpp:142
std::chrono::system_clock::time_point parse_compact_expiry(std::string_view text)
Reads Kiwoom's token expiry, yyyyMMddHHmmss in Korean time.
Definition config.hpp:65
constexpr bool kiwoom_position_scope_asserted(KiwoomPositionScope scope) noexcept
Tests whether a holdings scope states what Kiwoom's holdings figure covers, so holdings may be read a...
Definition config.hpp:124
KiwoomPositionScope
What the venue named on a Kiwoom holdings request (kt00018's dmst_stex_tp) means for the positions it...
Definition config.hpp:102
@ UNSPECIFIED
Not stated: every new order and amendment is refused (cancellations are not), and the session's holdi...
Definition config.hpp:107
@ VALUATION_ONLY
Asserted: the venue only selects which venue's price values each position, and every position is list...
Definition config.hpp:112
The library: broker-neutral types (core), and the modules below.
Venue
A trading venue: an exchange, or the combined view across exchanges.
Definition types.hpp:43
Kiwoom credentials (app key and secret key), demo or real account, the market-data tape,...
Definition config.hpp:154
void from_json_impl(const std::string &filename)
Reads the credentials from a JSON file; called by from_json(filename). Nothing changes if it throws.
Definition config.hpp:233
static constexpr std::string_view secret_field() noexcept
The JSON field Kiwoom expects the application secret under.
Definition config.hpp:313
const char * rest_port() const noexcept
The REST port, which is the same for both environments.
Definition config.hpp:327
const char * ws_host() const noexcept
The WebSocket host for the selected environment.
Definition config.hpp:333
KiwoomPositionScope holdings_position_scope_
Your assertion of what holdings_venue_ means for the positions listed. No default: until it is set,...
Definition config.hpp:193
bool is_demo_
Whether to use Kiwoom's demo (모의투자) endpoints; true unless stated otherwise.
Definition config.hpp:162
static constexpr std::string_view key_field() noexcept
The JSON field Kiwoom expects the application key under.
Definition config.hpp:307
MarketTape market_tape_
Which venue's prices every Kiwoom market-data request reads (quotes, depth, trades,...
Definition config.hpp:170
std::string tape_symbol(std::string_view symbol) const
Returns a symbol with this configuration's tape suffix, for a market-data request.
Definition config.hpp:348
KiwoomSellableScope holdings_sellable_scope_
Your assertion of what a holdings row's tradable quantity covers; separate from the position scope,...
Definition config.hpp:202
const char * ws_port() const noexcept
The WebSocket port, which is the same for both environments.
Definition config.hpp:341
static bool demo_from_json(const json::object &doc, const std::string &filename)
Reads a credential file's "demo".
Definition config.hpp:289
void from_env_impl()
Reads the credentials from KIWOOM_APP_KEY and KIWOOM_SECRET_KEY, and the environment from KIWOOM_DEMO...
Definition config.hpp:209
static bool demo_from_env()
Reads KIWOOM_DEMO.
Definition config.hpp:268
const char * rest_host() const noexcept
The REST host for the selected environment.
Definition config.hpp:319
Venue holdings_venue_
The venue holdings requests (kt00018) name: Venue::KRX or Venue::NXT. No default: holdings requests a...
Definition config.hpp:182
A Kiwoom REST access token (au10001's token) and its expiry (expires_dt).
Definition config.hpp:354
std::string token_type_
Kiwoom's token_type (bearer in its example).
Definition config.hpp:356
static constexpr std::string_view token_field() noexcept
The field Kiwoom returns the bearer token under.
Definition config.hpp:362
void from_json_impl(const json::object &doc)
Reads the expiry (expires_dt, the only one Kiwoom states) and token_type; called by from_json....
Definition config.hpp:369
An OAuth access token and its expiry, the base of each broker's token-response class.
Definition oauth.hpp:131
std::chrono::system_clock::time_point expires_at_
Definition oauth.hpp:135