Tutorial
KiwoomRestApi.Net ๋ง์คํฐ๋ฅผ ์ํ ๋จ๊ณ๋ณ ๊ฐ์ด๋์ ๋๋ค.
Getting Started
SetupPrerequisites
- .NET 6.0 ์ด์
- Visual Studio 2022 ๋๋ VS Code
- ํค์์ฆ๊ถ ๊ณ์ ๋ฐ API ์ ๊ทผ ๊ถํ
- ํค์ OpenAPI์์ ๋ฐ๊ธ๋ฐ์ ์ฑ ํค์ ์ํฌ๋ฆฟ ํค
Installation
NuGet ํจํค์ง๋ฅผ ์ค์นํ์ธ์:
dotnet add package KiwoomRestApi.Net
Tip: NuGet ํจํค์ง ๊ด๋ฆฌ์ ์ฝ์์์๋ ์ค์นํ ์ ์์ต๋๋ค:
Install-Package KiwoomRestApi.Net
Basic Project Setup
using KiwoomRestApi.Net.Clients;
var appKey = "YOUR_APP_KEY";
var secretKey = "YOUR_SECRET_KEY";
var isMock = true; // ์ค๊ฑฐ๋์ ๊ฒฝ์ฐ false๋ก ์ค์
// ํด๋ผ์ด์ธํธ ์์ฑ
var client = KiwoomRestApiClient.Create(appKey, secretKey, isMock);Basic Usage
DataGetting Stock Information
์ผ์ฑ์ ์(005930)์ ๊ธฐ๋ณธ ์ฃผ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ ๋ณด๊ฒ ์ต๋๋ค:
using KiwoomRestApi.Net.Enums.StockInfo;
// ์ผ์ฑ์ ์(005930) ์ฃผ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
var stockInfo = await client.StockInfo.GetStockInfoAsync(
stockCode: "005930",
date: DateTime.Today,
marginLoanType: KiwoomStockInfoMarginLoanType.Loan
);
if (stockInfo.IsSuccess)
{
Console.WriteLine($"์ฃผ์๋ช
: {stockInfo.Data?.StockName}");
Console.WriteLine($"ํ์ฌ๊ฐ: {stockInfo.Data?.CurrentPrice:N0} KRW");
Console.WriteLine($"๋ณ๋๋ฅ : {stockInfo.Data?.ChangeRate:F2}%");
Console.WriteLine($"๊ฑฐ๋๋: {stockInfo.Data?.Volume:N0}");
}
else
{
Console.WriteLine($"์ค๋ฅ: {stockInfo.ReturnMessage}");
}Understanding the Response
๋ชจ๋ API ํธ์ถ์ KiwoomRestApiResponse<T> ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค:
| Property | Type | Description |
|---|---|---|
IsSuccess | bool | API ํธ์ถ ์ฑ๊ณต ์ฌ๋ถ |
Data | T? | ์๋ต ๋ฐ์ดํฐ |
ReturnMessage | string? | ์๋ต ๋ฉ์์ง |
ApiId | string | API ์๋ณ์ |
ContYn | bool | ํ์ด์ง๋ค์ด์ ์ฐ์ ํ๋๊ทธ |
NextKey | string | ๋ค์ ํ์ด์ง ํค |
Account Management
DataGetting Account Balance
using KiwoomRestApi.Net.Enums.Account;
// ํ๊ฐ ์๊ณ ๊ฐ์ ธ์ค๊ธฐ
var balances = await client.Account.GetEvaluationBalancesAsync(
queryType: KiwoomAccountEvaluationBalanceQueryType.Aggregate,
domesticStockExchangeType: KiwoomAccountDomesticStockExchangeType2.Krx
);
if (balances.IsSuccess)
{
foreach (var balance in balances.Data?.Items)
{
Console.WriteLine($"์ด์์ฐ: {balance.TotalEvaluationAmount:N0} KRW");
Console.WriteLine($"์ด ์์ต: {balance.TotalEvaluationProfitLossAmount:N0} KRW");
Console.WriteLine($"์์ต๋ฅ : {balance.TotalProfitRate:F2}%");
}
}Getting Daily Status
// ์ผ๋ณ ๊ณ์ข ์ํ ๊ฐ์ ธ์ค๊ธฐ
var dailyStatus = await client.Account.GetDailyStatusAsync();
if (dailyStatus.IsSuccess)
{
Console.WriteLine($"์
๊ธ์ก: {dailyStatus.Data?.DepositAmount:N0} KRW");
Console.WriteLine($"์ด ๋งค์: {dailyStatus.Data?.BuyAmount:N0} KRW");
Console.WriteLine($"์ด ๋งค๋: {dailyStatus.Data?.SellAmount:N0} KRW");
}
Warning: ์ผ๋ถ ๊ณ์ข API๋ ๋ชจ์ํฌ์ ๋ชจ๋์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ ์ฒด ๊ธฐ๋ฅ์ ์ํด ์ค์ API ํค๋ฅผ ์ฌ์ฉํ์ธ์.
Stock Information
DataMarket Data & Quotes
// ํ์ฌ ์์ฅ ํธ๊ฐ ๊ฐ์ ธ์ค๊ธฐ
var quote = await client.MarketCondition.GetQuoteAsync("005930");
if (quote.IsSuccess)
{
Console.WriteLine($"ํ์ฌ๊ฐ: {quote.Data?.CurrentPrice}");
Console.WriteLine($"์ต์ฐ์ ๋งค์๊ฐ: {quote.Data?.BuyPrice1}");
Console.WriteLine($"์ต์ฐ์ ๋งค๋๊ฐ: {quote.Data?.SellPrice1}");
}
// ํธ๊ฐ์ฐฝ ๊ฐ์ ธ์ค๊ธฐ
var orderBook = await client.MarketCondition.GetOrderBookListAsync("005930");
if (orderBook.IsSuccess)
{
Console.WriteLine("ํธ๊ฐ์ฐฝ:");
var quotes = orderBook.Data;
for (int i = 0; i < 5; i++)
{
Console.WriteLine($" ๋งค๋ {i+1}: {quotes?.SellQuotes[i].Price} ({quotes?.SellQuotes[i].Quantity})");
}
Console.WriteLine(" --------------------");
for (int i = 0; i < 5; i++)
{
Console.WriteLine($" ๋งค์ {i+1}: {quotes?.BuyQuotes[i].Price} ({quotes?.BuyQuotes[i].Quantity})");
}
}Ranking Information
using KiwoomRestApi.Net.Enums.RankingInfo;
// ์์ ์์น์ข
๊ฐ์ ธ์ค๊ธฐ
var gainers = await client.RankingInfo.GetChangeRateTopsAsync(
marketType: KiwoomRankingInfoMarketType.All,
sortType: KiwoomRankingInfoChangeSortType.Up,
minVolume: 100,
stockCondition: KiwoomRankingInfoStockCondition.All,
creditCondition: KiwoomRankingInfoCreditCondition.All,
isIncludeUpDown: true,
priceCondition: KiwoomRankingInfoPriceCondition.All,
minTransactionAmount: 1000,
stockExchangeType: KiwoomRankingInfoStockExchangeType.Unified
);
if (gainers.IsSuccess)
{
Console.WriteLine("์์ ์์น์ข
:");
foreach (var stock in gainers.Data?.Items.Take(5) ?? Enumerable.Empty<KiwoomRankingInfoGetChangeRateTopItem>())
{
Console.WriteLine($"{stock.StockName}: {stock.ChangeRate:F2}% ({stock.CurrentPrice})");
}
}
// ๊ฑฐ๋๋ ์์ ์ข
๋ชฉ ๊ฐ์ ธ์ค๊ธฐ
var activeStocks = await client.RankingInfo.GetTodayVolumeTopsAsync(
marketType: KiwoomRankingInfoMarketType.All,
sortType: KiwoomRankingInfoVolumeSortType.Volume,
stockCondition: KiwoomRankingInfoStockCondition.All,
creditCondition: KiwoomRankingInfoCreditCondition.All,
minVolume: 100,
priceCondition: KiwoomRankingInfoPriceCondition2.All,
minTransactionAmount: 1000,
marketOpenType: KiwoomRankingInfoMarketOpenType.All,
stockExchangeType: KiwoomRankingInfoStockExchangeType.Unified
);
if (activeStocks.IsSuccess)
{
Console.WriteLine("๊ฑฐ๋๋ ์์ ์ข
๋ชฉ:");
foreach (var stock in activeStocks.Data?.Items.Take(5) ?? Enumerable.Empty<KiwoomRankingInfoGetTodayVolumeTopItem>())
{
Console.WriteLine($"{stock.StockName}: {stock.Volume:N0} ์ฃผ");
}
}Trading Operations
Trading
Important: ๊ฑฐ๋ ์์
์ ์ค์ API ํค๊ฐ ํ์ํ๋ฉฐ ์ฃผ์ํด์ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ํ
์คํธ๋ฅผ ์ํด ๋ชจ์ํฌ์ ๋ชจ๋๋ก ์์ํ์ธ์.
Placing Orders
using KiwoomRestApi.Net.Enums.Order;
// ๋งค์ ์ฃผ๋ฌธ ์์ (์์ฅ๊ฐ)
var buyOrder = await client.Order.PlaceOrderAsync(
KiwoomOrderType.Buy,
KiwoomOrderDomesticStockExchangeType.Krx,
stockCode: "005930",
orderQuantity: 10,
KiwoomOrderTransactionType.Market
);
if (buyOrder.IsSuccess)
{
Console.WriteLine($"์ฃผ๋ฌธ ์ฑ๊ณต. ์ฃผ๋ฌธ๋ฒํธ: {buyOrder.Data?.OrderId}");
}
// ์ง์ ๊ฐ ์ฃผ๋ฌธ ์์
var limitOrder = await client.Order.PlaceOrderAsync(
KiwoomOrderType.Buy,
KiwoomOrderDomesticStockExchangeType.Krx,
stockCode: "005930",
orderQuantity: 10,
KiwoomOrderTransactionType.Limit,
orderPrice: 75000 // ์ง์ ๊ฐ
);Order Management
// ๋ฏธ์ฒด๊ฒฐ ์ฃผ๋ฌธ ๊ฐ์ ธ์ค๊ธฐ
var unfilledOrders = await client.Account.GetUnfilledOrdersAsync(
KiwoomAccountQueryType.All,
KiwoomAccountTransactionType.All,
KiwoomAccountStockExchangeType.Unified
);
if (unfilledOrders.IsSuccess)
{
foreach (var order in unfilledOrders.Data?.Items)
{
Console.WriteLine($"์ฃผ๋ฌธ: {order.OrderId} - {order.StockName}");
Console.WriteLine($"์ ํ: {order.TaskType}, ์๋: {order.OrderQuantity}");
}
}
// ์ฃผ๋ฌธ ์ทจ์
var cancelResult = await client.Order.CancelOrderAsync(
KiwoomOrderDomesticStockExchangeType.Krx,
originalOrderId: "YOUR_ORDER_NUMBER",
stockCode: "005930",
cancelQuantity: 5
);
// ์ฃผ๋ฌธ ์์
var modifyResult = await client.Order.ModifyOrderAsync(
KiwoomOrderDomesticStockExchangeType.Krx,
originalOrderId: "YOUR_ORDER_NUMBER",
stockCode: "005930",
modifyQuantity: 15,
modifyPrice: 76000
);Chart Data
DataBasic Charts
๋ค์ํ ์ฃผ๊ธฐ์ ์ฐจํธ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ์ ์์ต๋๋ค:
using KiwoomRestApi.Net.Enums.Chart;
var stockCode = "005930";
var date = new DateTime(2026, 3, 1);
// ์ผ๋ด ์ฐจํธ
var daily = await client.Chart.GetDailyChartsAsync(stockCode, date, false);
// ์ฃผ๋ด ์ฐจํธ
var weekly = await client.Chart.GetWeeklyChartsAsync(stockCode, date, false);
// ์๋ด ์ฐจํธ
var monthly = await client.Chart.GetMonthlyChartsAsync(stockCode, date, false);
// ๋ถ๋ด ์ฐจํธ (15๋ถ)
var minute = await client.Chart.GetMinuteChartsAsync(stockCode, 15, date, false);
// ํฑ ์ฐจํธ (30ํฑ)
var tick = await client.Chart.GetTickChartsAsync(stockCode, 30, false);Range Charts
ํน์ ๊ธฐ๊ฐ์ ์ฐจํธ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ์๋ ์์ต๋๋ค:
var startDate = new DateTime(2026, 1, 1);
var endDate = new DateTime(2026, 3, 6);
// ๊ธฐ๊ฐ๋ณ ์ผ๋ด ์ฐจํธ
var dailyRange = await client.Chart.GetDailyChartsByRangeAsync(stockCode, startDate, endDate, false);
// ๊ธฐ๊ฐ๋ณ ๋ถ๋ด ์ฐจํธ
var minuteRange = await client.Chart.GetMinuteChartsByRangeAsync(stockCode, 15, startDate, endDate, false);Industry Charts
// ์
์ข
์ผ๋ด ์ฐจํธ
var industryDaily = await client.Chart.GetIndustryDailyChartsAsync(
KiwoomChartIndustryCode.Kospi200, date);
// ์
์ข
๋ถ๋ด ์ฐจํธ (15๋ถ)
var industryMinute = await client.Chart.GetIndustryMinuteChartsAsync(
KiwoomChartIndustryCode.Kospi200, 15, date);Gold Spot Charts
using KiwoomRestApi.Net.Enums.Chart;
// ๊ธํ๋ฌผ ํฑ ์ฐจํธ
var goldTick = await client.Chart.GetGoldSpotTickChartsAsync(
KiwoomGoldSpotStockCode.Gold_1kg, 10, true);
// ๊ธํ๋ฌผ ์ผ๋ด ์ฐจํธ
var goldDaily = await client.Chart.GetGoldSpotDailyChartsAsync(
KiwoomGoldSpotStockCode.Gold_1kg, date, true);Real-time Data
WebSocketSetting up WebSocket Client
using KiwoomRestApi.Net.Enums.WebSocket;
// ์์ผ ํด๋ผ์ด์ธํธ ์์ฑ
var socketClient = KiwoomSocketClient.Create(client.Token, isMock: true);
// ์ค์๊ฐ ์ฃผ์ ์ฒด๊ฒฐ ๋ฐ์ดํฐ ๊ตฌ๋
await socketClient.WebSocket.SubscribeAsync(
serviceNames: [KiwoomWebSocketServiceName.StockTrade],
parameters: ["005930", "000660", "035420"],
groupId: "1"
);Handling Real-time Events
// ์ฃผ์ ์ฒด๊ฒฐ ์ด๋ฒคํธ
socketClient.OnRealtimeStockTradeReceived += (realtimeData) =>
{
foreach (var data in realtimeData)
{
Console.WriteLine($"[{data.Item}] {data.Values.CurrentPrice} " +
$"({data.Values.ChangeRate:F2}%) " +
$"๊ฑฐ๋๋: {data.Values.AccumulatedVolume:N0}");
}
};
// ์ฃผ๋ฌธ ์ฒด๊ฒฐ ์ด๋ฒคํธ
socketClient.OnRealtimeOrderTradeReceived += (orderData) =>
{
foreach (var order in orderData)
{
Console.WriteLine($"์ฃผ๋ฌธ ์
๋ฐ์ดํธ: {order.Values.OrderId} - {order.Values.OrderStatus}");
}
};
// ์๊ณ ์ด๋ฒคํธ
socketClient.OnRealtimeBalanceReceived += (balanceData) =>
{
foreach (var balance in balanceData)
{
Console.WriteLine($"์๊ณ ์
๋ฐ์ดํธ: {balance.Values.StockName}");
Console.WriteLine($"๋ณด์ ์๋: {balance.Values.HoldingQuantity}");
}
};Available Services
| Service | Enum Value | Description |
|---|---|---|
| ์ฃผ์ ์ฒด๊ฒฐ | StockTrade | ์ค์๊ฐ ์ฃผ์ ์ฒด๊ฒฐ ๋ฐ์ดํฐ |
| ์ฃผ์ ํธ๊ฐ | OrderBook | ์ค์๊ฐ ํธ๊ฐ ๋ฐ์ดํฐ |
| ์๊ณ | Balance | ์ค์๊ฐ ์๊ณ ๋ณ๋ |
| ์ฃผ๋ฌธ ์ฒด๊ฒฐ | OrderTrade | ์ค์๊ฐ ์ฃผ๋ฌธ ์ฒด๊ฒฐ |
| VI ๋ฐ๋ | ViEvent | VI(๋ณ๋์ฑ ์ํ์ฅ์น) ๋ฐ๋ |
| ETF NAV | EtfNav | ETF NAV ๋ฐ์ดํฐ |
Advanced Features
AdvancedPagination
๋๋์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ๋ ํ์ด์ง๋ค์ด์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค:
// ์ฒซ ํ์ด์ง ์กฐํ
var firstPage = await client.Chart.GetTickChartsAsync("005930", 1, false);
// ๋ค์ ํ์ด์ง๊ฐ ์์ผ๋ฉด
if (firstPage.ContYn)
{
client.ContYn = true;
client.NextKey = firstPage.NextKey;
var secondPage = await client.Chart.GetTickChartsAsync("", 1, false);
// ์ด๊ธฐํ
client.ContYn = false;
client.NextKey = "";
}Pagination Loop
๋ชจ๋ ํ์ด์ง๋ฅผ ์ํํ๋ ๋ฐฉ๋ฒ์ ๋๋ค:
// ๋ชจ๋ ํ์ด์ง๋ฅผ ์ํํ๋ ๋ฃจํ
var response = await client.Chart.GetTickChartsAsync("005930", 1, false);
while (response.IsSuccess)
{
foreach (var item in response.Data?.Items ?? Enumerable.Empty<KiwoomChartGetTickChartItem>())
{
Console.WriteLine($"{item.CurrentPrice}");
}
if (!response.ContYn) break;
client.ContYn = true;
client.NextKey = response.NextKey;
response = await client.Chart.GetTickChartsAsync("", 1, false);
}
client.ContYn = false;
client.NextKey = "";Gold Spot Trading
using KiwoomRestApi.Net.Enums.Order;
using KiwoomRestApi.Net.Enums.Chart;
// ๊ธํ๋ฌผ ๋งค์ ์ฃผ๋ฌธ
var goldBuy = await client.Order.GoldSpotPlaceOrderAsync(
KiwoomOrderType.Buy,
KiwoomGoldSpotStockCode.MiniGold_100g,
orderQuantity: 1,
KiwoomOrderGoldSpotTransactionType.Normal
);
// ๊ธํ๋ฌผ ์๊ณ ์กฐํ
var goldBalances = await client.Account.GetGoldEvaluationBalancesAsync();
// ๊ธํ๋ฌผ ์์๊ธ ์กฐํ
var goldDeposit = await client.Account.GetGoldDepositAsync(
KiwoomAccountEvaluationBalanceQueryType.Aggregate,
KiwoomAccountDomesticStockExchangeType.All
);Condition Search
// ์กฐ๊ฑด๊ฒ์ ๋ชฉ๋ก ์กฐํ
await socketClient.WebSocket.GetConditionSearchListAsync();
// ์กฐ๊ฑด๊ฒ์ ์ค์๊ฐ ๊ตฌ๋
await socketClient.WebSocket.GetConditionSearchRequestRealtimeAsync(1);Error Handling
AdvancedHandling API Errors
try
{
var result = await client.StockInfo.GetStockInfoAsync(
stockCode: "005930",
date: DateTime.Today,
marginLoanType: KiwoomStockInfoMarginLoanType.Loan
);
if (!result.IsSuccess)
{
Console.WriteLine($"API Error [{result.ApiId}]: {result.ReturnMessage}");
return;
}
// ์ฑ๊ณต ์ฒ๋ฆฌ
Console.WriteLine($"Stock: {result.Data?.StockName}");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"HTTP Error: {ex.Message}");
}
catch (TaskCanceledException)
{
Console.WriteLine("Request timed out.");
}
catch (Exception ex)
{
Console.WriteLine($"Unexpected error: {ex.Message}");
}
Note: API ์ค๋ฅ๋
IsSuccess == false๋ก ๋ฐํ๋ฉ๋๋ค. ๋คํธ์ํฌ ์ค๋ฅ ๋ฑ์ ์์ธ๋ก ๋ฐ์ํฉ๋๋ค.
Best Practices
SetupConnection Management
// IDisposable์ ํ์ฉํ ์ ์ ํ ํด์
using var client = KiwoomRestApiClient.Create(appKey, secretKey, isMock);
using var socketClient = KiwoomSocketClient.Create(client.Token, isMock);
// API ํธ์ถ...Rate Limiting
API ํธ์ถ ์ ์๋ ์ ํ์ ๊ตฌํํ๋ ๊ฒ์ด ์ข์ต๋๋ค:
// PagingDelay ์์ฑ์ ํ์ฉํ ํ์ด์ง๋ค์ด์
์ง์ฐ
client.PagingDelay = 1000; // ํ์ด์ง ๊ฐ 1์ด ์ง์ฐ (ms)
// ๋๋ SemaphoreSlim์ ์ฌ์ฉํ ์๋ ์ ํ
private readonly SemaphoreSlim _semaphore = new(1, 1);
public async Task<T> ExecuteWithLimitAsync<T>(Func<Task<T>> apiCall)
{
await _semaphore.WaitAsync();
try
{
var result = await apiCall();
await Task.Delay(TimeSpan.FromMilliseconds(100));
return result;
}
finally
{
_semaphore.Release();
}
}
Pro Tip: ๊ฐ๋ฐ ๋ฐ ํ
์คํธ ์์๋ ํญ์ ๋ชจ์ํฌ์ ๋ชจ๋๋ก ์์ํ์ธ์. ํ๋ก๋์
์ค๋น๊ฐ ๋์์ ๋๋ง ์ค์ API ํค๋ก ์ ํํ์ธ์.