Skip to content

Commit

Permalink
filter 삭제, 핵심함수 private 삭제, 우선순위 큐 만들기, websocket 데이터 등록 관련 구조 변경 (#233)
Browse files Browse the repository at this point in the history
  • Loading branch information
swkim12345 authored Nov 24, 2024
2 parents 949878f + cdfd1f8 commit fd85580
Show file tree
Hide file tree
Showing 18 changed files with 497 additions and 271 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,5 @@ report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# vscode setting
.vscode

# remote
.remote
3 changes: 2 additions & 1 deletion packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
"test:e2e": "jest --config ./test/jest-e2e.json",
"mem": "node ../../dist/main --inspect"
},
"dependencies": {
"@nestjs/common": "^10.0.0",
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Inject, Injectable, UseFilters } from '@nestjs/common';
import { Inject, Injectable } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';
import { Between, DataSource } from 'typeorm';
import { Logger } from 'winston';
import { openApiConfig } from '../config/openapi.config';
import { OpenapiExceptionFilter } from '../Decorator/openapiException.filter';
import {
DetailDataQuery,
FinancialRatio,
Expand Down Expand Up @@ -35,8 +34,7 @@ export class OpenapiDetailData {
}

@Cron('0 8 * * 1-5')
@UseFilters(OpenapiExceptionFilter)
public async getDetailData() {
async getDetailData() {
if (process.env.NODE_ENV !== 'production') return;
const entityManager = this.datasource.manager;
const stocks = await entityManager.find(Stock);
Expand Down Expand Up @@ -197,7 +195,7 @@ export class OpenapiDetailData {
return output1[0];
}
} catch (error) {
this.logger.error(error);
this.logger.warn(error);
}
}

Expand All @@ -215,10 +213,9 @@ export class OpenapiDetailData {
if (response.output) {
const output2 = response.output;
return output2;
//return bufferToObject(output2);
}
} catch (error) {
this.logger.error(error);
this.logger.warn(error);
}
}

Expand Down
120 changes: 28 additions & 92 deletions packages/backend/src/scraper/openapi/api/openapiLiveData.api.ts
Original file line number Diff line number Diff line change
@@ -1,100 +1,36 @@
import { Inject } from '@nestjs/common';
import { EntityManager } from 'typeorm';
import { Logger } from 'winston';
import { openApiConfig } from '../config/openapi.config';
import { StockData, parseStockData } from '../type/openapiLiveData.type';
import { decryptAES256 } from '../util/openapiUtil.api';
import { openApiToken } from './openapiToken.api';
import { KospiStock } from '@/stock/domain/kospiStock.entity';
import { Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { StockLiveData } from '@/stock/domain/stockLiveData.entity';

@Injectable()
export class OpenapiLiveData {
public readonly TR_ID: string = 'H0STCNT0';
private readonly WEBSOCKET_MAX: number = 40;
constructor(
@Inject('winston') private readonly logger: Logger,
private readonly manager: EntityManager,
) {}

public async getMessage(): Promise<string[]> {
const kospi = await this.getKospiStockId();
const config = openApiToken.configs;
const configLength = config.length;
const ret: string[] = [];

for (let i = 0; i < configLength; i++) {
const stocks = kospi.splice(
i * this.WEBSOCKET_MAX,
(i + 1) * this.WEBSOCKET_MAX,
);
for (const stock of stocks) {
ret.push(this.convertObjectToMessage(config[i], stock.id!));
}
}

return ret;
}

private convertObjectToMessage(
config: typeof openApiConfig,
stockId: string,
): string {
const message = {
header: {
approval_key: config.STOCK_WEBSOCKET_KEY!,
custtype: 'P',
tr_type: '1',
'content-type': 'utf-8',
},
body: {
input: {
tr_id: this.TR_ID,
tr_key: stockId,
},
},
};
return JSON.stringify(message);
}

private async getKospiStockId() {
const kospi = await this.manager.find(KospiStock);
return kospi;
}

private async saveLiveData(data: StockLiveData) {
await this.manager.save(StockLiveData, data);
}

private convertLiveData(message: string[]): StockLiveData {
const stockData: StockData = parseStockData(message);
const stockLiveData = new StockLiveData();
stockLiveData.currentPrice = parseFloat(stockData.STCK_PRPR);
stockLiveData.changeRate = parseFloat(stockData.PRDY_CTRT);
stockLiveData.volume = parseInt(stockData.CNTG_VOL);
stockLiveData.high = parseFloat(stockData.STCK_HGPR);
stockLiveData.low = parseFloat(stockData.STCK_LWPR);
stockLiveData.open = parseFloat(stockData.STCK_OPRC);
stockLiveData.previousClose = parseFloat(stockData.WGHN_AVRG_STCK_PRC);
stockLiveData.updatedAt = new Date();

return stockLiveData;
constructor(private readonly datasource: DataSource) {}

async saveLiveData(data: StockLiveData[]) {
await this.datasource.manager
.getRepository(StockLiveData)
.createQueryBuilder()
.insert()
.into(StockLiveData)
.values(data)
.execute();
}

public async output(message: Buffer, iv?: string, key?: string) {
const parsed = message.toString().split('|');
if (parsed.length > 0) {
if (parsed[0] == '1' && iv && key)
parsed[4] = decryptAES256(parsed[4], iv, key);
if (parsed[1] !== this.TR_ID) return;
const stockData = parsed[4].split('^');
const length = stockData.length / parseInt(parsed[3]);
const size = parseInt(parsed[2]);
const i = 0;
while (i < size) {
const data = stockData.splice(i * length, (i + 1) * length);
const liveData = this.convertLiveData(data);
this.saveLiveData(liveData);
}
}
convertLiveData(messages: Record<string, string>[]): StockLiveData[] {
const stockData: StockLiveData[] = [];
messages.map((message) => {
const stockLiveData = new StockLiveData();
stockLiveData.currentPrice = parseFloat(message.STCK_PRPR);
stockLiveData.changeRate = parseFloat(message.PRDY_CTRT);
stockLiveData.volume = parseInt(message.CNTG_VOL);
stockLiveData.high = parseFloat(message.STCK_HGPR);
stockLiveData.low = parseFloat(message.STCK_LWPR);
stockLiveData.open = parseFloat(message.STCK_OPRC);
stockLiveData.previousClose = parseFloat(message.WGHN_AVRG_STCK_PRC);
stockLiveData.updatedAt = new Date();
stockData.push(stockLiveData);
});
return stockData;
}
}
19 changes: 10 additions & 9 deletions packages/backend/src/scraper/openapi/api/openapiMinuteData.api.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Injectable, UseFilters } from '@nestjs/common';
import { Inject, Injectable } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';
import { DataSource } from 'typeorm';
import { Logger } from 'winston';
import { openApiConfig } from '../config/openapi.config';
import { OpenapiExceptionFilter } from '../Decorator/openapiException.filter';

import {
isMinuteData,
MinuteData,
Expand All @@ -24,13 +25,15 @@ export class OpenapiMinuteData {
'/uapi/domestic-stock/v1/quotations/inquire-time-itemchartprice';
private readonly intervals: number = 130;
private flip: number = 0;
public constructor(private readonly datasource: DataSource) {
constructor(
private readonly datasource: DataSource,
@Inject('winston') private readonly logger: Logger,
) {
this.getStockData();
}

@Cron('0 1 * * 1-5')
@UseFilters(OpenapiExceptionFilter)
private async getStockData() {
async getStockData() {
if (process.env.NODE_ENV !== 'production') return;
const stock = await this.datasource.manager.findBy(Stock, {
isTrading: true,
Expand Down Expand Up @@ -104,11 +107,10 @@ export class OpenapiMinuteData {
this.saveMinuteData(stockId, output, time);
}
} catch (error) {
console.error(error);
this.logger.warn(error);
}
}

@UseFilters(OpenapiExceptionFilter)
private async getMinuteDataChunk(
chunk: Stock[],
config: typeof openApiConfig,
Expand All @@ -125,8 +127,7 @@ export class OpenapiMinuteData {
}

@Cron(`*/${STOCK_CUT} 9-15 * * 1-5`)
@UseFilters(OpenapiExceptionFilter)
private getMinuteData() {
getMinuteData() {
if (process.env.NODE_ENV !== 'production') return;
const configCount = openApiToken.configs.length;
const stock = this.stock[this.flip % STOCK_CUT];
Expand Down
Loading

0 comments on commit fd85580

Please sign in to comment.