rwadurian/backend/services/trading-service/src/api/controllers/trading.controller.ts

120 lines
4.0 KiB
TypeScript

import { Controller, Get, Post, Param, Query, Body, NotFoundException, Req } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery, ApiBearerAuth } from '@nestjs/swagger';
import { OrderService } from '../../application/services/order.service';
import { OrderRepository } from '../../infrastructure/persistence/repositories/order.repository';
import { TradingAccountRepository } from '../../infrastructure/persistence/repositories/trading-account.repository';
import { OrderType } from '../../domain/aggregates/order.aggregate';
class CreateOrderDto {
type: 'BUY' | 'SELL';
price: string;
quantity: string;
}
@ApiTags('Trading')
@ApiBearerAuth()
@Controller('trading')
export class TradingController {
constructor(
private readonly orderService: OrderService,
private readonly orderRepository: OrderRepository,
private readonly accountRepository: TradingAccountRepository,
) {}
@Get('accounts/:accountSequence')
@ApiOperation({ summary: '获取交易账户信息' })
@ApiParam({ name: 'accountSequence', description: '账户序号' })
async getAccount(@Param('accountSequence') accountSequence: string) {
const account = await this.accountRepository.findByAccountSequence(accountSequence);
if (!account) {
throw new NotFoundException('Account not found');
}
return {
accountSequence: account.accountSequence,
shareBalance: account.shareBalance.toString(),
cashBalance: account.cashBalance.toString(),
availableShares: account.availableShares.toString(),
availableCash: account.availableCash.toString(),
frozenShares: account.frozenShares.toString(),
frozenCash: account.frozenCash.toString(),
totalBought: account.totalBought.toString(),
totalSold: account.totalSold.toString(),
};
}
@Get('orderbook')
@ApiOperation({ summary: '获取订单簿' })
@ApiQuery({ name: 'limit', required: false, type: Number })
async getOrderBook(@Query('limit') limit?: number) {
return this.orderRepository.getOrderBook(limit ?? 20);
}
@Post('orders')
@ApiOperation({ summary: '创建订单' })
async createOrder(@Body() dto: CreateOrderDto, @Req() req: any) {
const accountSequence = req.user?.accountSequence;
if (!accountSequence) {
throw new Error('Unauthorized');
}
return this.orderService.createOrder(
accountSequence,
dto.type === 'BUY' ? OrderType.BUY : OrderType.SELL,
dto.price,
dto.quantity,
);
}
@Post('orders/:orderNo/cancel')
@ApiOperation({ summary: '取消订单' })
@ApiParam({ name: 'orderNo', description: '订单号' })
async cancelOrder(@Param('orderNo') orderNo: string, @Req() req: any) {
const accountSequence = req.user?.accountSequence;
if (!accountSequence) {
throw new Error('Unauthorized');
}
await this.orderService.cancelOrder(accountSequence, orderNo);
return { success: true };
}
@Get('orders')
@ApiOperation({ summary: '获取用户订单列表' })
@ApiQuery({ name: 'page', required: false, type: Number })
@ApiQuery({ name: 'pageSize', required: false, type: Number })
async getOrders(
@Req() req: any,
@Query('page') page?: number,
@Query('pageSize') pageSize?: number,
) {
const accountSequence = req.user?.accountSequence;
if (!accountSequence) {
throw new Error('Unauthorized');
}
const result = await this.orderRepository.findByAccountSequence(accountSequence, {
page: page ?? 1,
pageSize: pageSize ?? 50,
});
return {
data: result.data.map((o) => ({
id: o.id,
orderNo: o.orderNo,
type: o.type,
status: o.status,
price: o.price.toString(),
quantity: o.quantity.toString(),
filledQuantity: o.filledQuantity.toString(),
remainingQuantity: o.remainingQuantity.toString(),
averagePrice: o.averagePrice.toString(),
totalAmount: o.totalAmount.toString(),
createdAt: o.createdAt,
completedAt: o.completedAt,
cancelledAt: o.cancelledAt,
})),
total: result.total,
};
}
}