algotradelib 0.0.0.9000
C++ header-only library for algorithmic trading
Loading...
Searching...
No Matches
errors.hpp
1#pragma once
2
3#include "../../core/types.hpp"
4
5#include <boost/json.hpp>
6
7#include <optional>
8#include <string>
9#include <string_view>
10
11namespace algotradelib::kiwoom {
12
27
33inline KiwoomRateLimitLayer kiwoom_rate_limit_layer(std::string_view code) noexcept {
34 if (code == "1700") {
36 }
37 if (code == "1701") {
39 }
40 if (code == "1702") {
42 }
44}
45
62inline ErrorCategory kiwoom_error_category(std::string_view code) noexcept {
63 // Header-level authentication faults: the authorization field is missing or malformed.
64 if (code == "1512" || code == "1513" || code == "1514" || code == "1515" || code == "1516") {
66 }
67 // Availability, not authentication. Checked before the 80xx sweep below, which it sits inside.
68 if (code == "8104" || code == "8200") {
70 }
71 // The key, the token, the terminal, or the registered IP.
72 if (code.size() == 4 && code.front() == '8') {
74 }
77 }
78 // 재귀 호출이 발생하여 API 호출을 제한합니다: a throttle, stated as one.
79 if (code == "1687") {
81 }
82 if (code == "1501" || code == "1504" || code == "1505" || code == "1511" || code == "1517" ||
83 code == "1901" || code == "1902" || code == "1903") {
85 }
87}
88
97inline std::optional<BrokerError> kiwoom_declared_error(const boost::json::object& document) {
98 const auto code = document.if_contains("return_code");
99 if (!code) {
100 return std::nullopt;
101 }
102 std::string text;
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());
109 } else {
110 BrokerError error;
112 error.broker_code_ = "invalid_return_code";
113 error.message_ = "return_code is neither a number nor a string";
114 return error;
115 }
116 if (text == "0") {
117 return std::nullopt;
118 }
119
120 BrokerError error;
121 error.broker_code_ = text;
122 error.reached_broker_ = true;
123 if (const auto message = document.if_contains("return_msg"); message && message->is_string()) {
124 error.message_ = std::string(message->as_string());
125 } else {
126 error.message_ = "Kiwoom declared return_code " + text;
127 }
128 error.category_ = kiwoom_error_category(text);
129 return error;
130}
131
148
160inline std::string_view kiwoom_refusal_code(std::string_view message) noexcept {
161 constexpr std::string_view prefix = "[2000](";
162 if (message.size() < prefix.size() || message.substr(0, prefix.size()) != prefix || message.back() != ')') {
163 return {};
164 }
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()) {
168 return {};
169 }
170 const auto code = inner.substr(0, colon);
171 for (const char character : code) {
172 if (!((character >= 'A' && character <= 'Z') || (character >= '0' && character <= '9'))) {
173 return {};
174 }
175 }
176 return code;
177}
178
204inline std::optional<BrokerError> kiwoom_recognized_refusal(
205 int http_status,
206 const boost::json::object& document,
207 KiwoomOrderOperation operation,
208 bool demo
209) {
210 if (http_status != 200) {
211 return std::nullopt;
212 }
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")
217 );
218 const auto message = document.if_contains("return_msg");
219 if (!generic || !message || !message->is_string()) {
220 return std::nullopt;
221 }
222 const std::string stated(kiwoom_refusal_code(std::string_view(message->as_string())));
223 const char* name = "";
224 const bool placement = operation == KiwoomOrderOperation::PLACE &&
225 (demo ? (stated == "800033" || stated == "RC4057" || stated == "RC4058") : stated == "571445");
226 const bool cancellation = operation == KiwoomOrderOperation::CANCEL &&
227 (demo ? stated == "RC4033" : stated == "506550");
228 if (placement) {
229 name = "placement";
230 } else if (cancellation) {
231 name = "cancellation";
232 } else {
233 return std::nullopt;
234 }
235 if (const auto number = document.if_contains("ord_no");
236 number && !(number->is_string() && number->as_string().empty())) {
237 return std::nullopt;
238 }
239 for (const char* field : {"cncl_qty", "mdfy_qty"}) {
240 const auto quantity = document.if_contains(field);
241 if (!quantity) {
242 continue;
243 }
244 if (!quantity->is_string() ||
245 std::string_view(quantity->as_string()).find_first_not_of('0') != std::string_view::npos) {
246 return std::nullopt;
247 }
248 }
249 BrokerError error;
251 error.reached_broker_ = true;
252 error.http_status_ = http_status;
253 error.broker_code_ = stated;
254 error.message_ = std::string(message->as_string()) + " (return_code 20; recognized refusal: Kiwoom " +
255 (demo ? "demo" : "real") + ", cash " + name + ", " + stated + ")";
256 return error;
257}
258
259} // namespace algotradelib::kiwoom
The Kiwoom Securities REST API client.
Definition auth.hpp:12
KiwoomRateLimitLayer kiwoom_rate_limit_layer(std::string_view code) noexcept
Classifies a Kiwoom return code as a rate-limit refusal.
Definition errors.hpp:33
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 ...
Definition errors.hpp:97
KiwoomRateLimitLayer
Which of Kiwoom's three rate limits a refusal reports (per API, account-wide, or per API group); back...
Definition errors.hpp:17
@ ENDPOINT
1700: this API's own allowance.
Definition errors.hpp:21
@ TOTAL
1701: the total allowance across every API.
Definition errors.hpp:23
@ GROUP
1702: the allowance of the API group this endpoint belongs to.
Definition errors.hpp:25
KiwoomOrderOperation
Which order instruction a reply answers.
Definition errors.hpp:138
@ CANCEL
A cancellation (kt10003).
Definition errors.hpp:146
@ UNCLASSIFIED
Not an order request, or one this client does not classify.
Definition errors.hpp:140
@ PLACE
A placement (kt10000, kt10001).
Definition errors.hpp:142
ErrorCategory kiwoom_error_category(std::string_view code) noexcept
Classifies a Kiwoom return_code.
Definition errors.hpp:62
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...
Definition errors.hpp:160
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.
Definition errors.hpp:204
ErrorCategory
The kind of failure a BrokerError reports.
Definition types.hpp:687
@ RATE_LIMIT
The broker refused the request for its rate limit.
Definition types.hpp:697
@ PROTOCOL
The reply could not be read, or the broker declared a failure this client does not classify further: ...
Definition types.hpp:704
@ AUTHENTICATION
The credentials or token were refused.
Definition types.hpp:695
@ INVALID_ARGUMENT
The request was invalid, refused by the client before sending or by the broker.
Definition types.hpp:713
The error a broker or transport operation returns.
Definition types.hpp:742
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....
Definition types.hpp:759
std::string message_
A human-readable description, for logs; do not parse it.
Definition types.hpp:772
ErrorCategory category_
The kind of failure; the field to branch on.
Definition types.hpp:744
std::string broker_code_
The broker's own error code, verbatim (for example KIS's EGW00201).
Definition types.hpp:761
bool reached_broker_
Whether a request was sent before this error.
Definition types.hpp:753