Skip to content

Commit

Permalink
Merge pull request #37 from boostcampwm-2024/feature/api/stockindex-#6
Browse files Browse the repository at this point in the history
[#6] 3.02 주식차트 정보 기능 구현 수정
  • Loading branch information
sieunie authored Nov 7, 2024
2 parents 33c45c7 + 89420d7 commit 8a36bb1
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 84 deletions.
6 changes: 3 additions & 3 deletions BE/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand All @@ -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 {}
33 changes: 18 additions & 15 deletions BE/src/stock/index/dto/stock.index.response.dto.ts
Original file line number Diff line number Diff line change
@@ -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;
}
16 changes: 16 additions & 0 deletions BE/src/stock/index/dto/stock.index.response.element.dto.ts
Original file line number Diff line number Diff line change
@@ -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;
}
7 changes: 0 additions & 7 deletions BE/src/stock/index/interface/stock.index.interface.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
92 changes: 72 additions & 20 deletions BE/src/stock/index/stock.index.controller.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
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')
export class StockIndexController {
constructor(
private readonly stockIndexService: StockIndexService,
private readonly koreaInvestmentService: KoreaInvestmentService,
private readonly socketGateway: SocketGateway,
) {}

@Get()
Expand All @@ -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',
Expand All @@ -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);
}
}
3 changes: 2 additions & 1 deletion BE/src/stock/index/stock.index.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
11 changes: 11 additions & 0 deletions BE/src/websocket/socket.module.ts
Original file line number Diff line number Diff line change
@@ -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 {}
43 changes: 5 additions & 38 deletions BE/src/websocket/socket.service.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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();
Expand All @@ -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],
Expand All @@ -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',
Expand All @@ -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();
Expand Down

0 comments on commit 8a36bb1

Please sign in to comment.