120 lines
4.0 KiB
TypeScript
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,
|
|
};
|
|
}
|
|
}
|