3#include "../../core/types.hpp"
5#include <boost/json.hpp>
64 if (code ==
"1512" || code ==
"1513" || code ==
"1514" || code ==
"1515" || code ==
"1516") {
68 if (code ==
"8104" || code ==
"8200") {
72 if (code.size() == 4 && code.front() ==
'8') {
82 if (code ==
"1501" || code ==
"1504" || code ==
"1505" || code ==
"1511" || code ==
"1517" ||
83 code ==
"1901" || code ==
"1902" || code ==
"1903") {
98 const auto code = document.if_contains(
"return_code");
103 if (code->is_int64()) {
104 text = std::to_string(code->as_int64());
105 }
else if (code->is_uint64()) {
106 text = std::to_string(code->as_uint64());
107 }
else if (code->is_string()) {
108 text = std::string(code->as_string());
113 error.
message_ =
"return_code is neither a number nor a string";
123 if (
const auto message = document.if_contains(
"return_msg"); message && message->is_string()) {
124 error.
message_ = std::string(message->as_string());
126 error.
message_ =
"Kiwoom declared return_code " + text;
161 constexpr std::string_view prefix =
"[2000](";
162 if (message.size() < prefix.size() || message.substr(0, prefix.size()) != prefix || message.back() !=
')') {
165 const auto inner = message.substr(prefix.size(), message.size() - prefix.size() - 1);
166 const auto colon = inner.find(
':');
167 if (colon == std::string_view::npos || colon == 0 || colon + 1 == inner.size()) {
170 const auto code = inner.substr(0, colon);
171 for (
const char character : code) {
172 if (!((character >=
'A' && character <=
'Z') || (character >=
'0' && character <=
'9'))) {
206 const boost::json::object& document,
210 if (http_status != 200) {
213 const auto code = document.if_contains(
"return_code");
214 const bool generic = code && (
215 (code->is_int64() && code->as_int64() == 20) || (code->is_uint64() && code->as_uint64() == 20) ||
216 (code->is_string() && code->as_string() ==
"20")
218 const auto message = document.if_contains(
"return_msg");
219 if (!generic || !message || !message->is_string()) {
223 const char* name =
"";
225 (demo ? (stated ==
"800033" || stated ==
"RC4057" || stated ==
"RC4058") : stated ==
"571445");
227 (demo ? stated ==
"RC4033" : stated ==
"506550");
230 }
else if (cancellation) {
231 name =
"cancellation";
235 if (
const auto number = document.if_contains(
"ord_no");
236 number && !(number->is_string() && number->as_string().empty())) {
239 for (
const char* field : {
"cncl_qty",
"mdfy_qty"}) {
240 const auto quantity = document.if_contains(field);
244 if (!quantity->is_string() ||
245 std::string_view(quantity->as_string()).find_first_not_of(
'0') != std::string_view::npos) {
254 error.
message_ = std::string(message->as_string()) +
" (return_code 20; recognized refusal: Kiwoom " +
255 (demo ?
"demo" :
"real") +
", cash " + name +
", " + stated +
")";
The Kiwoom Securities REST API client.
KiwoomRateLimitLayer kiwoom_rate_limit_layer(std::string_view code) noexcept
Classifies a Kiwoom return code as a rate-limit refusal.
std::optional< BrokerError > kiwoom_declared_error(const boost::json::object &document)
Reads the failure a Kiwoom response declares in its body (Kiwoom reports business failures with HTTP ...
KiwoomRateLimitLayer
Which of Kiwoom's three rate limits a refusal reports (per API, account-wide, or per API group); back...
@ ENDPOINT
1700: this API's own allowance.
@ TOTAL
1701: the total allowance across every API.
@ GROUP
1702: the allowance of the API group this endpoint belongs to.
@ NONE
Not a rate-limit code.
KiwoomOrderOperation
Which order instruction a reply answers.
@ CANCEL
A cancellation (kt10003).
@ AMEND
An amendment (kt10002).
@ UNCLASSIFIED
Not an order request, or one this client does not classify.
@ PLACE
A placement (kt10000, kt10001).
ErrorCategory kiwoom_error_category(std::string_view code) noexcept
Classifies a Kiwoom return_code.
std::string_view kiwoom_refusal_code(std::string_view message) noexcept
Reads the code inside an order refusal's return_msg, which Kiwoom writes as [2000](CODE:text) under t...
std::optional< BrokerError > kiwoom_recognized_refusal(int http_status, const boost::json::object &document, KiwoomOrderOperation operation, bool demo)
Reads the refusal a cash-order reply states, for the replies this client recognizes as one.
ErrorCategory
The kind of failure a BrokerError reports.
@ RATE_LIMIT
The broker refused the request for its rate limit.
@ PROTOCOL
The reply could not be read, or the broker declared a failure this client does not classify further: ...
@ AUTHENTICATION
The credentials or token were refused.
@ INVALID_ARGUMENT
The request was invalid, refused by the client before sending or by the broker.
The error a broker or transport operation returns.
int http_status_
The HTTP status of the reply: set for an HTTP error and for a reply whose body is not a JSON object....
std::string message_
A human-readable description, for logs; do not parse it.
ErrorCategory category_
The kind of failure; the field to branch on.
std::string broker_code_
The broker's own error code, verbatim (for example KIS's EGW00201).
bool reached_broker_
Whether a request was sent before this error.