Skip to content

Commit

Permalink
๐Ÿ”ง fix: stock-order-socket๊ณผ stock-order ์„œ๋น„์Šค๊ฐ€ ์ˆœํ™˜์ฐธ์กฐ ํ•˜์ง€ ์•Š๊ฒŒ ์ˆ˜์ • #53
Browse files Browse the repository at this point in the history
- ๊ฐ socket service๋ฅผ ๊ฐ ๊ธฐ๋Šฅ ๋ชจ๋“ˆ์— ์ข…์†๋˜๋„๋ก ์ˆ˜์ •ํ•จ.
  • Loading branch information
sieunie committed Nov 14, 2024
1 parent 8276c03 commit b0b13e6
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 157 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common';
import { StockIndexValueElementDto } from '../../../stock/index/dto/stock-index-value-element.dto';
import { BaseSocketService } from '../../base-socket.service';
import { SocketGateway } from '../../socket.gateway';
import { StockIndexValueElementDto } from './dto/stock-index-value-element.dto';
import { BaseSocketService } from '../../websocket/base-socket.service';
import { SocketGateway } from '../../websocket/socket.gateway';

@Injectable()
export class StockIndexSocketService {
Expand Down
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 @@ -3,10 +3,11 @@ 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';
import { StockIndexSocketService } from './stock-index-socket.service';

@Module({
imports: [KoreaInvestmentModule, SocketModule],
controllers: [StockIndexController],
providers: [StockIndexService],
providers: [StockIndexService, StockIndexSocketService],
})
export class StockIndexModule {}
119 changes: 119 additions & 0 deletions BE/src/stock/order/stock-order-socket.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import {
Injectable,
InternalServerErrorException,
Logger,
} from '@nestjs/common';
import { LessThanOrEqual, MoreThanOrEqual } from 'typeorm';
import { BaseSocketService } from '../../websocket/base-socket.service';
import { SocketGateway } from '../../websocket/socket.gateway';
import { Order } from './stock-order.entity';
import { TradeType } from './enum/trade-type';
import { StatusType } from './enum/status-type';
import { StockOrderRepository } from './stock-order.repository';

@Injectable()
export class StockOrderSocketService {
private TR_ID = 'H0STCNT0';

private readonly logger = new Logger();

constructor(
private readonly socketGateway: SocketGateway,
private readonly baseSocketService: BaseSocketService,
private readonly stockOrderRepository: StockOrderRepository,
) {
baseSocketService.registerSocketOpenHandler(async () => {
const orders: Order[] =
await this.stockOrderRepository.findAllCodeByStatus();
orders.forEach((order) => {
baseSocketService.registerCode(this.TR_ID, order.stock_code);
});
});

baseSocketService.registerSocketDataHandler(
this.TR_ID,
(data: string[]) => {
this.checkExecutableOrder(
data[0], // ์ฃผ์‹ ์ฝ”๋“œ
data[2], // ์ฃผ์‹ ์ฒด๊ฒฐ๊ฐ€
).catch(() => {
throw new InternalServerErrorException();
});
},
);
}

subscribeByCode(trKey: string) {
this.baseSocketService.registerCode(this.TR_ID, trKey);
}

unsubscribeByCode(trKey: string) {
this.baseSocketService.unregisterCode(this.TR_ID, trKey);
}

private async checkExecutableOrder(stockCode: string, value) {
const buyOrders = await this.stockOrderRepository.find({
where: {
stock_code: stockCode,
trade_type: TradeType.BUY,
status: StatusType.PENDING,
price: MoreThanOrEqual(value),
},
});

const sellOrders = await this.stockOrderRepository.find({
where: {
stock_code: stockCode,
trade_type: TradeType.SELL,
status: StatusType.PENDING,
price: LessThanOrEqual(value),
},
});

await Promise.all(buyOrders.map((buyOrder) => this.executeBuy(buyOrder)));
await Promise.all(
sellOrders.map((sellOrder) => this.executeSell(sellOrder)),
);

if (
!(await this.stockOrderRepository.existsBy({
stock_code: stockCode,
status: StatusType.PENDING,
}))
)
this.unsubscribeByCode(stockCode);
}

private async executeBuy(order) {
this.logger.log(`${order.id}๋ฒˆ ๋งค์ˆ˜ ์˜ˆ์•ฝ์ด ์ฒด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`, 'BUY');

const totalPrice = order.price * order.amount;
const fee = this.calculateFee(totalPrice);
await this.stockOrderRepository.updateOrderAndAssetWhenBuy(
order,
totalPrice + fee,
);
}

private async executeSell(order) {
this.logger.log(`${order.id}๋ฒˆ ๋งค๋„ ์˜ˆ์•ฝ์ด ์ฒด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`, 'SELL');

const totalPrice = order.price * order.amount;
const fee = this.calculateFee(totalPrice);
await this.stockOrderRepository.updateOrderAndAssetWhenSell(
order,
totalPrice - fee,
);
}

private calculateFee(totalPrice: number) {
if (totalPrice <= 10000000) return totalPrice * 0.16;
if (totalPrice > 10000000 && totalPrice <= 50000000)
return totalPrice * 0.14;
if (totalPrice > 50000000 && totalPrice <= 100000000)
return totalPrice * 0.12;
if (totalPrice > 100000000 && totalPrice <= 300000000)
return totalPrice * 0.1;
return totalPrice * 0.08;
}
}
12 changes: 4 additions & 8 deletions BE/src/stock/order/stock-order.module.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import { forwardRef, Module } from '@nestjs/common';
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { StockOrderController } from './stock-order.controller';
import { StockOrderService } from './stock-order.service';
import { Order } from './stock-order.entity';
import { StockOrderRepository } from './stock-order.repository';
import { SocketModule } from '../../websocket/socket.module';
import { AssetModule } from '../../asset/asset.module';
import { StockOrderSocketService } from './stock-order-socket.service';

@Module({
imports: [
TypeOrmModule.forFeature([Order]),
forwardRef(() => SocketModule),
AssetModule,
],
imports: [TypeOrmModule.forFeature([Order]), SocketModule, AssetModule],
controllers: [StockOrderController],
providers: [StockOrderService, StockOrderRepository],
exports: [StockOrderService],
providers: [StockOrderService, StockOrderRepository, StockOrderSocketService],
})
export class StockOrderModule {}
85 changes: 5 additions & 80 deletions BE/src/stock/order/stock-order.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import {
ConflictException,
ForbiddenException,
forwardRef,
Inject,
Injectable,
Logger,

Check failure on line 5 in BE/src/stock/order/stock-order.service.ts

View workflow job for this annotation

GitHub Actions / BE-test-and-build

'Logger' is defined but never used
} from '@nestjs/common';
Expand All @@ -12,22 +10,15 @@ import { StockOrderRequestDto } from './dto/stock-order-request.dto';
import { StockOrderRepository } from './stock-order.repository';
import { TradeType } from './enum/trade-type';
import { StatusType } from './enum/status-type';
import { StockPriceSocketService } from '../../websocket/stock/price/stock-price-socket.service';
import { StockOrderSocketService } from './stock-order-socket.service';

@Injectable()
export class StockOrderService {
constructor(
private readonly stockOrderRepository: StockOrderRepository,
@Inject(forwardRef(() => StockPriceSocketService))
private readonly stockPriceSocketService: StockPriceSocketService,
private readonly stockOrderSocketService: StockOrderSocketService,
) {}

private readonly logger = new Logger();

async findAllPendingOrderCode() {
return this.stockOrderRepository.findAllCodeByStatus();
}

async buy(userId: number, stockOrderRequest: StockOrderRequestDto) {
const order = this.stockOrderRepository.create({
user_id: userId,
Expand All @@ -39,7 +30,7 @@ export class StockOrderService {
});

await this.stockOrderRepository.save(order);
this.stockPriceSocketService.subscribeByCode(stockOrderRequest.stock_code);
this.stockOrderSocketService.subscribeByCode(stockOrderRequest.stock_code);
}

async sell(userId: number, stockOrderRequest: StockOrderRequestDto) {
Expand All @@ -53,7 +44,7 @@ export class StockOrderService {
});

await this.stockOrderRepository.save(order);
this.stockPriceSocketService.subscribeByCode(stockOrderRequest.stock_code);
this.stockOrderSocketService.subscribeByCode(stockOrderRequest.stock_code);
}

async cancel(userId: number, orderId: number) {
Expand All @@ -75,72 +66,6 @@ export class StockOrderService {
status: StatusType.PENDING,
}))
)
this.stockPriceSocketService.unsubscribeByCode(order.stock_code);
}

async checkExecutableOrder(stockCode: string, value) {
const buyOrders = await this.stockOrderRepository.find({
where: {
stock_code: stockCode,
trade_type: TradeType.BUY,
status: StatusType.PENDING,
price: MoreThanOrEqual(value),
},
});

const sellOrders = await this.stockOrderRepository.find({
where: {
stock_code: stockCode,
trade_type: TradeType.SELL,
status: StatusType.PENDING,
price: LessThanOrEqual(value),
},
});

await Promise.all(buyOrders.map((buyOrder) => this.executeBuy(buyOrder)));
await Promise.all(
sellOrders.map((sellOrder) => this.executeSell(sellOrder)),
);

if (
!(await this.stockOrderRepository.existsBy({
stock_code: stockCode,
status: StatusType.PENDING,
}))
)
this.stockPriceSocketService.unsubscribeByCode(stockCode);
}

private async executeBuy(order) {
this.logger.log(`${order.id}๋ฒˆ ๋งค์ˆ˜ ์˜ˆ์•ฝ์ด ์ฒด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`, 'BUY');

const totalPrice = order.price * order.amount;
const fee = this.calculateFee(totalPrice);
await this.stockOrderRepository.updateOrderAndAssetWhenBuy(
order,
totalPrice + fee,
);
}

private async executeSell(order) {
this.logger.log(`${order.id}๋ฒˆ ๋งค๋„ ์˜ˆ์•ฝ์ด ์ฒด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`, 'SELL');

const totalPrice = order.price * order.amount;
const fee = this.calculateFee(totalPrice);
await this.stockOrderRepository.updateOrderAndAssetWhenSell(
order,
totalPrice - fee,
);
}

private calculateFee(totalPrice: number) {
if (totalPrice <= 10000000) return totalPrice * 0.16;
if (totalPrice > 10000000 && totalPrice <= 50000000)
return totalPrice * 0.14;
if (totalPrice > 50000000 && totalPrice <= 100000000)
return totalPrice * 0.12;
if (totalPrice > 100000000 && totalPrice <= 300000000)
return totalPrice * 0.1;
return totalPrice * 0.08;
this.stockOrderSocketService.unsubscribeByCode(order.stock_code);
}
}
17 changes: 3 additions & 14 deletions BE/src/websocket/socket.module.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
import { forwardRef, Module } from '@nestjs/common';
import { StockIndexSocketService } from './stock/index/stock-index-socket.service';
import { Module } from '@nestjs/common';
import { SocketGateway } from './socket.gateway';
import { SocketTokenService } from './socket-token.service';
import { StockPriceSocketService } from './stock/price/stock-price-socket.service';
import { BaseSocketService } from './base-socket.service';
import { StockOrderModule } from '../stock/order/stock-order.module';

@Module({
imports: [forwardRef(() => StockOrderModule)],
controllers: [],
providers: [
SocketTokenService,
StockIndexSocketService,
SocketGateway,
StockPriceSocketService,
BaseSocketService,
],
exports: [SocketGateway, StockPriceSocketService],
providers: [SocketTokenService, SocketGateway, BaseSocketService],
exports: [SocketGateway, BaseSocketService],
})
export class SocketModule {}
51 changes: 0 additions & 51 deletions BE/src/websocket/stock/price/stock-price-socket.service.ts

This file was deleted.

0 comments on commit b0b13e6

Please sign in to comment.