106 lines
3.3 KiB
TypeScript
106 lines
3.3 KiB
TypeScript
|
|
import { ApiSettings, MarketType, OrderType, StockItem } from '../types';
|
|
import { API_BASE_URL, getHeaders } from './config';
|
|
|
|
/**
|
|
* Korea Investment & Securities (KIS) Open API Service
|
|
* Now connected to Real Backend
|
|
*/
|
|
export class KisService {
|
|
private settings: ApiSettings;
|
|
|
|
constructor(settings: ApiSettings) {
|
|
this.settings = settings;
|
|
}
|
|
|
|
async issueAccessToken() {
|
|
// Backend manages token automatically.
|
|
return "backend-managed-token";
|
|
}
|
|
|
|
async inquirePrice(code: string): Promise<number> {
|
|
// Default to Domestic for now, or infer from code length
|
|
const market = code.length === 6 ? "Domestic" : "Overseas";
|
|
try {
|
|
const res = await fetch(`${API_BASE_URL}/kis/price?market=${market}&code=${code}`);
|
|
if (!res.ok) return 0;
|
|
const data = await res.json();
|
|
return parseFloat(data.price) || 0;
|
|
} catch (e) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetch Market Data
|
|
*/
|
|
async fetchMasterStocks(market: MarketType): Promise<StockItem[]> {
|
|
try {
|
|
// Use Rankings as the default "List"
|
|
const marketParam = market === MarketType.DOMESTIC ? "Domestic" : "Overseas";
|
|
const res = await fetch(`${API_BASE_URL}/discovery/rankings?limit=50`);
|
|
if (!res.ok) return [];
|
|
const data = await res.json();
|
|
|
|
// Transform logic if needed. Ranking API returns StockItem which matches frontend type mostly.
|
|
return data.map((item: any) => ({
|
|
code: item.code,
|
|
name: item.name,
|
|
price: item.price,
|
|
change: item.change,
|
|
changePercent: item.changePercent,
|
|
market: market,
|
|
volume: 0, // Rankings might not return volume yet, or it does if enabled
|
|
aiScoreBuy: 50, // Placeholder as backend doesn't have AI score in StockItem yet
|
|
aiScoreSell: 50,
|
|
themes: []
|
|
}));
|
|
} catch (e) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
async orderCash(code: string, type: OrderType, quantity: number, price: number = 0) {
|
|
return this._placeOrder("Domestic", code, type, quantity, price);
|
|
}
|
|
|
|
async orderOverseas(code: string, type: OrderType, quantity: number, price: number) {
|
|
return this._placeOrder("Overseas", code, type, quantity, price);
|
|
}
|
|
|
|
private async _placeOrder(market: string, code: string, type: OrderType, quantity: number, price: number) {
|
|
const payload = {
|
|
market: market,
|
|
side: type === OrderType.BUY ? "buy" : "sell",
|
|
code: code,
|
|
quantity: quantity,
|
|
price: price
|
|
};
|
|
|
|
const res = await fetch(`${API_BASE_URL}/kis/order`, {
|
|
method: 'POST',
|
|
headers: getHeaders(),
|
|
body: JSON.stringify(payload)
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const err = await res.json();
|
|
throw new Error(err.detail || "Order Failed");
|
|
}
|
|
return await res.json();
|
|
}
|
|
|
|
async inquireBalance() {
|
|
// Default Domestic
|
|
const res = await fetch(`${API_BASE_URL}/kis/balance?market=Domestic`);
|
|
if (!res.ok) return { output1: [], output2: {} };
|
|
return await res.json();
|
|
}
|
|
|
|
async inquireBalanceOverseas() {
|
|
const res = await fetch(`${API_BASE_URL}/kis/balance?market=Overseas`);
|
|
if (!res.ok) return { output1: [], output2: {} };
|
|
return await res.json();
|
|
}
|
|
}
|