Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE] 6.04 매수/매도 요청 현황 API 구현 #92

Merged
merged 2 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions BE/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { SocketModule } from './websocket/socket.module';
import { StockOrderModule } from './stock/order/stock-order.module';
import { StockDetailModule } from './stock/detail/stock-detail.module';
import { typeOrmConfig } from './configs/typeorm.config';
import { StockTradeHistoryModule } from './stock/trade/history/stock-trade-history.module';

@Module({
imports: [
Expand All @@ -25,6 +26,7 @@ import { typeOrmConfig } from './configs/typeorm.config';
SocketModule,
StockDetailModule,
StockOrderModule,
StockTradeHistoryModule,
],
controllers: [AppController],
providers: [AppService],
Expand Down
18 changes: 18 additions & 0 deletions BE/src/stock/trade/history/dto/stock-trade-history-data.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ApiProperty } from '@nestjs/swagger';

export class StockTradeHistoryDataDto {
@ApiProperty({ description: '주식 체결 시간' })
stck_cntg_hour: string;

@ApiProperty({ description: '주식 현재가' })
stck_prpr: string;

@ApiProperty({ description: '전일 대비 부호' })
prdy_vrss_sign: string;

@ApiProperty({ description: '체결 거래량' })
cntg_vol: string;

@ApiProperty({ description: '전일 대비율' })
prdy_ctrt: string;
}
24 changes: 24 additions & 0 deletions BE/src/stock/trade/history/dto/stock-trade-history-output.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ApiProperty } from '@nestjs/swagger';

export class StockTradeHistoryOutputDto {
@ApiProperty({ description: '주식 체결 시간' })
stck_cntg_hour: string;

@ApiProperty({ description: '주식 현재가' })
stck_prpr: string;

@ApiProperty({ description: '전일 대비' })
prdy_vrss: string;

@ApiProperty({ description: '전일 대비 부호' })
prdy_vrss_sign: string;

@ApiProperty({ description: '체결 거래량' })
cntg_vol: string;

@ApiProperty({ description: '당일 체결강도' })
tday_rltv: string;

@ApiProperty({ description: '전일 대비율' })
prdy_ctrt: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* 주식현재가 체결 API를 사용할 때 쿼리 파라미터로 사용할 요청값 DTO
*/
export class StockTradeHistoryQueryParameterDto {
/**
* 조건 시장 분류 코드
* 'J' 주식
*/
fid_cond_mrkt_div_code: string;

/**
* 주식 종목 코드
* (ex) 005930
*/
fid_input_iscd: string;
}
10 changes: 10 additions & 0 deletions BE/src/stock/trade/history/dto/stock-trade-history-response.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ApiProperty } from '@nestjs/swagger';
import { StockTradeHistoryOutputDto } from './stock-trade-history-output.dto';

/**
* 주식현재가 체결 API 응답값 정제 후 FE에 보낼 DTO
*/
export class StockTradeHistoryResponseDto {
@ApiProperty({ type: StockTradeHistoryOutputDto, description: '상승률 순위' })
output: StockTradeHistoryOutputDto[];
}
16 changes: 16 additions & 0 deletions BE/src/stock/trade/history/interface/Inquire-ccnl.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export interface InquireCCNLOutputData {
stck_cntg_hour: string;
stck_prpr: string;
prdy_vrss: string;
prdy_vrss_sign: string;
cntg_vol: string;
tday_rltv: string;
prdy_ctrt: string;
}

export interface InquireCCNLApiResponse {
output: InquireCCNLOutputData[];
rt_cd: string;
msg_cd: string;
msg1: string;
}
29 changes: 29 additions & 0 deletions BE/src/stock/trade/history/stock-trade-history.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Controller, Get, Param } from '@nestjs/common';
import { ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger';
import { StockTradeHistoryService } from './stock-trade-history.service';
import { StockTradeHistoryResponseDto } from './dto/stock-trade-history-response.dto';

@Controller('/api/stocks')
export class StockTradeHistoryController {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 고생하셨습니당! 사소한 거지만 여기 ApiTags 빠진 것 같네용

constructor(
private readonly stockTradeHistoryService: StockTradeHistoryService,
) {}

@Get(':stockCode/trade-history')
@ApiOperation({ summary: '단일 주식 종목에 대한 주식현재가 체결 API' })
@ApiParam({
name: 'stockCode',
required: true,
description:
'종목 코드\n\n' +
'(ex) 005930 삼성전자 / 005380 현대차 / 001500 현대차증권',
})
@ApiResponse({
status: 200,
description: '단일 주식 종목에 대한 주식현재가 체결값 조회 성공',
type: StockTradeHistoryResponseDto,
})
getStockDetail(@Param('stockCode') stockCode: string) {
return this.stockTradeHistoryService.getStockTradeHistory(stockCode);
}
}
11 changes: 11 additions & 0 deletions BE/src/stock/trade/history/stock-trade-history.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { KoreaInvestmentModule } from '../../../koreaInvestment/korea-investment.module';
import { StockTradeHistoryController } from './stock-trade-history.controller';
import { StockTradeHistoryService } from './stock-trade-history.service';

@Module({
imports: [KoreaInvestmentModule],
controllers: [StockTradeHistoryController],
providers: [StockTradeHistoryService],
})
export class StockTradeHistoryModule {}
110 changes: 110 additions & 0 deletions BE/src/stock/trade/history/stock-trade-history.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import axios from 'axios';
import { Injectable, Logger } from '@nestjs/common';
import { KoreaInvestmentService } from '../../../koreaInvestment/korea-investment.service';
import { getHeader } from '../../../util/get-header';
import { getFullURL } from '../../../util/get-full-URL';
import { StockTradeHistoryQueryParameterDto } from './dto/stock-trade-history-query-parameter.dto';
import { InquireCCNLApiResponse } from './interface/Inquire-ccnl.interface';
import { StockTradeHistoryOutputDto } from './dto/stock-trade-history-output.dto';
import { StockTradeHistoryDataDto } from './dto/stock-trade-history-data.dto';

@Injectable()
export class StockTradeHistoryService {
private readonly logger = new Logger();

constructor(private readonly koreaInvetmentService: KoreaInvestmentService) {}

/**
* 특정 주식의 현재가 체결 데이터를 반환하는 함수
* @param {string} stockCode - 종목코드
* @returns - 특정 주식의 현재가 체결 데이터 객체 반환
*
* @author uuuo3o
*/
async getStockTradeHistory(stockCode: string) {
try {
const queryParams = new StockTradeHistoryQueryParameterDto();
queryParams.fid_cond_mrkt_div_code = 'J';
queryParams.fid_input_iscd = stockCode;

const response = await this.requestApi(queryParams);

return this.formatTradeHistoryData(response.output);
} catch (error) {
this.logger.error('API Error Details:', {
status: error.response?.status,
statusText: error.response?.statusText,
data: error.response?.data,
headers: error.response?.config?.headers, // 실제 요청 헤더
message: error.message,
});
throw error;
}
}

/**
* @private 한국투자 Open API - [국내주식] 기본시세 - 주식현재가 체결 호출 함수
* @param {StockTradeHistoryQueryParameterDto} queryParams - API 요청 시 필요한 쿼리 파라미터 DTO
* @returns - 주식현재가 체결 데이터
*
* @author uuuo3o
*/
private async requestApi(queryParams: StockTradeHistoryQueryParameterDto) {
try {
const accessToken = await this.koreaInvetmentService.getAccessToken();
const headers = getHeader(accessToken, 'FHKST01010300');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 이 requestAPI 함수 몇번 본거 같은데 Util 같은 곳에 KoreaInvestRequestAPI 이런 식으로 메소드 분리해서 사용하는 것도 좋을것 같습니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 진짜 좋은 거 같아요!
모든 API에서 저 함수 쓰고 있는데 리턴값 통일해서 하면 좋을 거 같네요ㅎㅎ 감사합니다!

const url = getFullURL('/uapi/domestic-stock/v1/quotations/inquire-ccnl');
const params = this.getTradeHistoryParams(queryParams);

const response = await axios.get<InquireCCNLApiResponse>(url, {
headers,
params,
});

return response.data;
} catch (error) {
this.logger.error('API Error Details:', {
status: error.response?.status,
statusText: error.response?.statusText,
data: error.response?.data,
headers: error.response?.config?.headers,
message: error.message,
});
throw error;
}
}

/**
* @private API에서 받은 주식현재가 체결 데이터를 필요한 정보로 정제하는 함수
* @param {StockTradeHistoryOutputDto} infos - API 응답에서 받은 원시 데이터
* @returns - 필요한 정보만 추출한 데이터 배열
*
* @author uuuo3o
*/
private formatTradeHistoryData(infos: StockTradeHistoryOutputDto[]) {
return infos.map((info) => {
const infoData = new StockTradeHistoryDataDto();
infoData.stck_cntg_hour = info.stck_cntg_hour;
infoData.stck_prpr = info.stck_prpr;
infoData.prdy_vrss_sign = info.prdy_vrss_sign;
infoData.cntg_vol = info.cntg_vol;
infoData.prdy_ctrt = info.prdy_ctrt;

return infoData;
});
}

/**
* @private 주식현재가 체결 요청을 위한 쿼리 파라미터 객체 생성 함수
* @param {StockTradeHistoryQueryParameterDto} params - API 요청에 필요한 쿼리 파라미터 DTO
* @returns - API 요청에 필요한 쿼리 파라미터 객체
*
* @author uuuo3o
*/
private getTradeHistoryParams(params: StockTradeHistoryQueryParameterDto) {
return {
fid_cond_mrkt_div_code: params.fid_cond_mrkt_div_code,
fid_input_iscd: params.fid_input_iscd,
};
}
}
Loading