"백엔드_핵심_로직_구현_프론트엔드_연동_및_도커_배포_최적화_완료"
This commit is contained in:
@@ -1,61 +1,105 @@
|
||||
|
||||
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;
|
||||
private accessToken: string | null = null;
|
||||
|
||||
constructor(settings: ApiSettings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
async issueAccessToken() {
|
||||
this.accessToken = "mock_token_" + Math.random().toString(36).substr(2);
|
||||
return this.accessToken;
|
||||
// Backend manages token automatically.
|
||||
return "backend-managed-token";
|
||||
}
|
||||
|
||||
async inquirePrice(code: string): Promise<number> {
|
||||
const basePrice = code.startsWith('0') ? 70000 : 150;
|
||||
return Math.floor(basePrice + Math.random() * 5000);
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 서버로부터 전체 종목 마스터 리스트를 가져오는 Mock 함수
|
||||
* Fetch Market Data
|
||||
*/
|
||||
async fetchMasterStocks(market: MarketType): Promise<StockItem[]> {
|
||||
console.log(`KIS: Fetching master stocks for ${market}...`);
|
||||
// 백엔드 구현 전까지는 시뮬레이션 데이터를 반환합니다.
|
||||
if (market === MarketType.DOMESTIC) {
|
||||
return [
|
||||
{ code: '005930', name: '삼성전자', price: 73200, change: 800, changePercent: 1.1, market: MarketType.DOMESTIC, volume: 15234000, aiScoreBuy: 85, aiScoreSell: 20, themes: ['반도체', 'AI', '스마트폰'] },
|
||||
{ code: '000660', name: 'SK하이닉스', price: 124500, change: -1200, changePercent: -0.96, market: MarketType.DOMESTIC, volume: 2100000, aiScoreBuy: 65, aiScoreSell: 45, themes: ['반도체', 'HBM'] },
|
||||
{ code: '035420', name: 'NAVER', price: 215000, change: 4500, changePercent: 2.14, market: MarketType.DOMESTIC, volume: 850000, aiScoreBuy: 72, aiScoreSell: 30, themes: ['플랫폼', 'AI'] },
|
||||
{ code: '035720', name: '카카오', price: 58200, change: 300, changePercent: 0.52, market: MarketType.DOMESTIC, volume: 1200000, aiScoreBuy: 50, aiScoreSell: 50, themes: ['플랫폼', '모빌리티'] },
|
||||
{ code: '005380', name: '현대차', price: 245000, change: 2000, changePercent: 0.82, market: MarketType.DOMESTIC, volume: 450000, aiScoreBuy: 78, aiScoreSell: 25, themes: ['자동차', '전기차'] },
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
{ code: 'AAPL', name: 'Apple Inc.', price: 189.43, change: 1.25, changePercent: 0.66, market: MarketType.OVERSEAS, volume: 45000000, aiScoreBuy: 90, aiScoreSell: 15, themes: ['빅테크', '스마트폰'] },
|
||||
{ code: 'TSLA', name: 'Tesla Inc.', price: 234.12, change: -4.50, changePercent: -1.89, market: MarketType.OVERSEAS, volume: 110000000, aiScoreBuy: 40, aiScoreSell: 75, themes: ['전기차', '자율주행'] },
|
||||
{ code: 'NVDA', name: 'NVIDIA Corp.', price: 485.12, change: 12.30, changePercent: 2.6, market: MarketType.OVERSEAS, volume: 32000000, aiScoreBuy: 95, aiScoreSell: 10, themes: ['반도체', 'AI'] },
|
||||
{ code: 'MSFT', name: 'Microsoft Corp.', price: 402.12, change: 3.45, changePercent: 0.86, market: MarketType.OVERSEAS, volume: 22000000, aiScoreBuy: 88, aiScoreSell: 12, themes: ['소프트웨어', 'AI'] },
|
||||
{ code: 'GOOGL', name: 'Alphabet Inc.', price: 145.12, change: 0.55, changePercent: 0.38, market: MarketType.OVERSEAS, volume: 18000000, aiScoreBuy: 75, aiScoreSell: 20, themes: ['검색', 'AI'] },
|
||||
];
|
||||
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 { success: true, orderId: "ORD-" + Math.random().toString(36).substr(2, 9) };
|
||||
return this._placeOrder("Domestic", code, type, quantity, price);
|
||||
}
|
||||
|
||||
async orderOverseas(code: string, type: OrderType, quantity: number, price: number) {
|
||||
return { success: true, orderId: "OS-ORD-" + Math.random().toString(36).substr(2, 9) };
|
||||
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() {
|
||||
return { output1: [], output2: { tot_evlu_amt: "124500000", nass_amt: "45800000" } };
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user