diff --git a/BE/src/app.module.ts b/BE/src/app.module.ts index 36681ad9..fbef051f 100644 --- a/BE/src/app.module.ts +++ b/BE/src/app.module.ts @@ -7,10 +7,9 @@ import { AppService } from './app.service'; import { AuthModule } from './auth/auth.module'; import { User } from './auth/user.entity'; import { StockIndexModule } from './stock/index/stock.index.module'; -import { SocketService } from './websocket/socket.service'; -import { SocketGateway } from './websocket/socket.gateway'; import { StockTopfiveModule } from './stock/topfive/stock.topfive.module'; import { KoreaInvestmentModule } from './koreaInvestment/korea.investment.module'; +import { SocketModule } from './websocket/socket.module'; @Module({ imports: [ @@ -30,8 +29,9 @@ import { KoreaInvestmentModule } from './koreaInvestment/korea.investment.module AuthModule, StockIndexModule, StockTopfiveModule, + SocketModule, ], controllers: [AppController], - providers: [AppService, SocketService, SocketGateway], + providers: [AppService], }) export class AppModule {} diff --git a/BE/src/stock/index/dto/stock.index.response.dto.ts b/BE/src/stock/index/dto/stock.index.response.dto.ts index 358266a5..7f26af32 100644 --- a/BE/src/stock/index/dto/stock.index.response.dto.ts +++ b/BE/src/stock/index/dto/stock.index.response.dto.ts @@ -1,25 +1,28 @@ import { ApiProperty } from '@nestjs/swagger'; -import { StockIndexListElementDto } from './stock.index.list.element.dto'; -import { StockIndexValueElementDto } from './stock.index.value.element.dto'; +import { StockIndexResponseElementDto } from './stock.index.response.element.dto'; export class StockIndexResponseDto { - constructor( - indexList: StockIndexListElementDto[], - indexValue: StockIndexValueElementDto[], - ) { - this.indexList = indexList; - this.indexValue = indexValue; - } + @ApiProperty({ + description: '코스피 지수', + type: StockIndexResponseElementDto, + }) + KOSPI: StockIndexResponseElementDto; + + @ApiProperty({ + description: '코스닥 지수', + type: StockIndexResponseElementDto, + }) + KOSDAQ: StockIndexResponseElementDto; @ApiProperty({ - description: '주가 지수 차트 정보 (코스피, 코스닥, 코스피200, KSQ150)', - type: [StockIndexListElementDto], + description: '코스피200 지수', + type: StockIndexResponseElementDto, }) - indexList: StockIndexListElementDto[]; + KOSPI200: StockIndexResponseElementDto; @ApiProperty({ - description: '주가 지수 실시간 값 정보 (코스피, 코스닥, 코스피200, KSQ150)', - type: [StockIndexValueElementDto], + description: 'KSQ150 지수', + type: StockIndexResponseElementDto, }) - indexValue: StockIndexValueElementDto[]; + KSQ150: StockIndexResponseElementDto; } diff --git a/BE/src/stock/index/dto/stock.index.response.element.dto.ts b/BE/src/stock/index/dto/stock.index.response.element.dto.ts new file mode 100644 index 00000000..7ce0ef1a --- /dev/null +++ b/BE/src/stock/index/dto/stock.index.response.element.dto.ts @@ -0,0 +1,16 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { StockIndexValueElementDto } from './stock.index.value.element.dto'; +import { StockIndexListElementDto } from './stock.index.list.element.dto'; + +export class StockIndexResponseElementDto { + @ApiProperty({ + description: '코스피: 0001, 코스닥: 1001, 코스피200: 2001, KSQ150: 3003', + }) + code: string; + + @ApiProperty({ description: '실시간 값', type: StockIndexValueElementDto }) + value: StockIndexValueElementDto; + + @ApiProperty({ description: '실시간 차트', type: StockIndexListElementDto }) + chart: StockIndexListElementDto; +} diff --git a/BE/src/stock/index/interface/stock.index.interface.ts b/BE/src/stock/index/interface/stock.index.interface.ts index 48d5851b..93636c51 100644 --- a/BE/src/stock/index/interface/stock.index.interface.ts +++ b/BE/src/stock/index/interface/stock.index.interface.ts @@ -1,10 +1,3 @@ -export interface AccessTokenInterface { - access_token: string; - access_token_token_expired: string; - token_type: string; - expires_in: number; -} - export interface StockIndexChartInterface { output: StockIndexChartElementInterface[]; rt_cd: string; diff --git a/BE/src/stock/index/stock.index.controller.ts b/BE/src/stock/index/stock.index.controller.ts index acc139b6..949df5a5 100644 --- a/BE/src/stock/index/stock.index.controller.ts +++ b/BE/src/stock/index/stock.index.controller.ts @@ -1,8 +1,10 @@ import { Controller, Get } from '@nestjs/common'; import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; +import { Cron } from '@nestjs/schedule'; import { StockIndexService } from './stock.index.service'; import { StockIndexResponseDto } from './dto/stock.index.response.dto'; import { KoreaInvestmentService } from '../../koreaInvestment/korea.investment.service'; +import { SocketGateway } from '../../websocket/socket.gateway'; @Controller('/api/stocks/index') @ApiTags('주가 지수 API') @@ -10,6 +12,7 @@ export class StockIndexController { constructor( private readonly stockIndexService: StockIndexService, private readonly koreaInvestmentService: KoreaInvestmentService, + private readonly socketGateway: SocketGateway, ) {} @Get() @@ -25,6 +28,74 @@ export class StockIndexController { async getStockIndex() { const accessToken = await this.koreaInvestmentService.getAccessToken(); + const [kospiChart, kosdaqChart, kospi200Chart, ksq150Chart] = + await Promise.all([ + this.stockIndexService.getDomesticStockIndexListByCode( + '0001', + accessToken, + ), // 코스피 + this.stockIndexService.getDomesticStockIndexListByCode( + '1001', + accessToken, + ), // 코스닥 + this.stockIndexService.getDomesticStockIndexListByCode( + '2001', + accessToken, + ), // 코스피200 + this.stockIndexService.getDomesticStockIndexListByCode( + '3003', + accessToken, + ), // KSQ150 + ]); + + const [kospiValue, kosdaqValue, kospi200Value, ksq150Value] = + await Promise.all([ + this.stockIndexService.getDomesticStockIndexValueByCode( + '0001', + accessToken, + ), // 코스피 + this.stockIndexService.getDomesticStockIndexValueByCode( + '1001', + accessToken, + ), // 코스닥 + this.stockIndexService.getDomesticStockIndexValueByCode( + '2001', + accessToken, + ), // 코스피200 + this.stockIndexService.getDomesticStockIndexValueByCode( + '3003', + accessToken, + ), // KSQ150 + ]); + + const stockIndexResponse = new StockIndexResponseDto(); + stockIndexResponse.KOSPI = { + code: '0001', + value: kospiValue, + chart: kospiChart, + }; + stockIndexResponse.KOSDAQ = { + code: '1001', + value: kosdaqValue, + chart: kosdaqChart, + }; + stockIndexResponse.KOSPI200 = { + code: '2001', + value: kospi200Value, + chart: kospi200Chart, + }; + stockIndexResponse.KSQ150 = { + code: '3003', + value: ksq150Value, + chart: ksq150Chart, + }; + return stockIndexResponse; + } + + @Cron('*/5 9-16 * * 1-5') + async cronStockIndexLists() { + const accessToken = await this.koreaInvestmentService.getAccessToken(); + const stockLists = await Promise.all([ this.stockIndexService.getDomesticStockIndexListByCode( '0001', @@ -44,25 +115,6 @@ export class StockIndexController { ), // KSQ150 ]); - const stockValues = await Promise.all([ - this.stockIndexService.getDomesticStockIndexValueByCode( - '0001', - accessToken, - ), // 코스피 - this.stockIndexService.getDomesticStockIndexValueByCode( - '1001', - accessToken, - ), // 코스닥 - this.stockIndexService.getDomesticStockIndexValueByCode( - '2001', - accessToken, - ), // 코스피200 - this.stockIndexService.getDomesticStockIndexValueByCode( - '3003', - accessToken, - ), // KSQ150 - ]); - - return new StockIndexResponseDto(stockLists, stockValues); + this.socketGateway.sendStockIndexListToClient(stockLists); } } diff --git a/BE/src/stock/index/stock.index.module.ts b/BE/src/stock/index/stock.index.module.ts index 2a044bf5..1227e4f7 100644 --- a/BE/src/stock/index/stock.index.module.ts +++ b/BE/src/stock/index/stock.index.module.ts @@ -2,9 +2,10 @@ import { Module } from '@nestjs/common'; import { StockIndexController } from './stock.index.controller'; import { StockIndexService } from './stock.index.service'; import { KoreaInvestmentModule } from '../../koreaInvestment/korea.investment.module'; +import { SocketModule } from '../../websocket/socket.module'; @Module({ - imports: [KoreaInvestmentModule], + imports: [KoreaInvestmentModule, SocketModule], controllers: [StockIndexController], providers: [StockIndexService], exports: [StockIndexService], diff --git a/BE/src/websocket/socket.module.ts b/BE/src/websocket/socket.module.ts new file mode 100644 index 00000000..4e9e2eb2 --- /dev/null +++ b/BE/src/websocket/socket.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { SocketService } from './socket.service'; +import { SocketGateway } from './socket.gateway'; + +@Module({ + imports: [], + controllers: [], + providers: [SocketService, SocketGateway], + exports: [SocketGateway], +}) +export class SocketModule {} diff --git a/BE/src/websocket/socket.service.ts b/BE/src/websocket/socket.service.ts index 0970d7a7..543517c0 100644 --- a/BE/src/websocket/socket.service.ts +++ b/BE/src/websocket/socket.service.ts @@ -1,10 +1,7 @@ import { Injectable, OnModuleInit } from '@nestjs/common'; import { WebSocket } from 'ws'; -import { Cron } from '@nestjs/schedule'; import { SocketGateway } from './socket.gateway'; import { StockIndexValueElementDto } from '../stock/index/dto/stock.index.value.element.dto'; -import { StockIndexService } from '../stock/index/stock.index.service'; -import { KoreaInvestmentService } from '../koreaInvestment/korea.investment.service'; @Injectable() export class SocketService implements OnModuleInit { @@ -13,11 +10,7 @@ export class SocketService implements OnModuleInit { H0UPCNT0: this.handleStockIndexValue.bind(this), }; - constructor( - private readonly stockIndexGateway: SocketGateway, - private readonly stockIndexService: StockIndexService, - private readonly koreaInvestmentService: KoreaInvestmentService, - ) {} + constructor(private readonly socketGateway: SocketGateway) {} async onModuleInit() { const socketConnectionKey = await this.getSocketConnectionKey(); @@ -43,35 +36,9 @@ export class SocketService implements OnModuleInit { }; } - @Cron('*/5 9-16 * * 1-5') - async cronStockIndexLists() { - const accessToken = await this.koreaInvestmentService.getAccessToken(); - - const stockLists = await Promise.all([ - this.stockIndexService.getDomesticStockIndexListByCode( - '0001', - accessToken, - ), // 코스피 - this.stockIndexService.getDomesticStockIndexListByCode( - '1001', - accessToken, - ), // 코스닥 - this.stockIndexService.getDomesticStockIndexListByCode( - '2001', - accessToken, - ), // 코스피200 - this.stockIndexService.getDomesticStockIndexListByCode( - '3003', - accessToken, - ), // KSQ150 - ]); - - this.stockIndexGateway.sendStockIndexListToClient(stockLists); - } - private handleStockIndexValue(responseData: string) { const responseList = responseData.split('^'); - this.stockIndexGateway.sendStockIndexValueToClient( + this.socketGateway.sendStockIndexValueToClient( new StockIndexValueElementDto( responseList[0], responseList[2], @@ -83,7 +50,7 @@ export class SocketService implements OnModuleInit { } private async getSocketConnectionKey() { - const url = 'https://openapi.koreainvestment.com:9443/oauth2/Approval'; + const url = `${process.env.KOREA_INVESTMENT_BASE_URL}/oauth2/Approval`; const response = await fetch(url, { method: 'POST', @@ -92,8 +59,8 @@ export class SocketService implements OnModuleInit { }, body: JSON.stringify({ grant_type: 'client_credentials', - appkey: process.env.APP_KEY, - secretkey: process.env.APP_SECRET, + appkey: process.env.KOREA_INVESTMENT_APP_KEY, + secretkey: process.env.KOREA_INVESTMENT_APP_SECRET, }), }); const result: SocketConnectTokenInterface = await response.json();