rwadurian/backend/services/trading-service/prisma/schema.prisma

284 lines
9.5 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// ==================== 交易账户 ====================
// 用户交易账户
model TradingAccount {
id String @id @default(uuid())
accountSequence String @unique
shareBalance Decimal @default(0) @db.Decimal(30, 8) // 积分股余额
cashBalance Decimal @default(0) @db.Decimal(30, 8) // 现金余额
frozenShares Decimal @default(0) @db.Decimal(30, 8) // 冻结积分股
frozenCash Decimal @default(0) @db.Decimal(30, 8) // 冻结现金
totalBought Decimal @default(0) @db.Decimal(30, 8) // 累计买入量
totalSold Decimal @default(0) @db.Decimal(30, 8) // 累计卖出量
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
orders Order[]
transactions TradingTransaction[]
@@map("trading_accounts")
}
// ==================== 订单 ====================
// 交易订单
model Order {
id String @id @default(uuid())
orderNo String @unique // 订单号
accountSequence String
type String // BUY, SELL
status String // PENDING, PARTIAL, FILLED, CANCELLED
price Decimal @db.Decimal(30, 18) // 挂单价格
quantity Decimal @db.Decimal(30, 8) // 订单数量
filledQuantity Decimal @default(0) @db.Decimal(30, 8) // 已成交数量
remainingQuantity Decimal @db.Decimal(30, 8) // 剩余数量
averagePrice Decimal @default(0) @db.Decimal(30, 18) // 平均成交价
totalAmount Decimal @default(0) @db.Decimal(30, 8) // 总成交金额
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
cancelledAt DateTime?
completedAt DateTime?
account TradingAccount @relation(fields: [accountSequence], references: [accountSequence])
trades Trade[]
@@index([accountSequence, status])
@@index([type, status, price])
@@index([createdAt(sort: Desc)])
@@map("orders")
}
// 成交记录
model Trade {
id String @id @default(uuid())
tradeNo String @unique
buyOrderId String
sellOrderId String
buyerSequence String
sellerSequence String
price Decimal @db.Decimal(30, 18)
quantity Decimal @db.Decimal(30, 8)
amount Decimal @db.Decimal(30, 8) // price * quantity
createdAt DateTime @default(now())
buyOrder Order @relation(fields: [buyOrderId], references: [id])
@@index([buyerSequence])
@@index([sellerSequence])
@@index([createdAt(sort: Desc)])
@@map("trades")
}
// ==================== 交易流水 ====================
model TradingTransaction {
id String @id @default(uuid())
accountSequence String
type String // TRANSFER_IN, TRANSFER_OUT, BUY, SELL, FREEZE, UNFREEZE, DEPOSIT, WITHDRAW
assetType String // SHARE, CASH
amount Decimal @db.Decimal(30, 8)
balanceBefore Decimal @db.Decimal(30, 8)
balanceAfter Decimal @db.Decimal(30, 8)
referenceId String?
referenceType String?
// 交易对手方信息关键用户ID和账户序列号
counterpartyType String? @map("counterparty_type") // USER, POOL, SYSTEM
counterpartyAccountSeq String? @map("counterparty_account_seq") // 对手方账户序列号
counterpartyUserId String? @map("counterparty_user_id") // 对手方用户ID
// 详细备注(包含完整交易信息,格式: "卖出给用户[U123456], 价格0.5USDT"
memo String? @db.Text
description String? // 保留兼容旧字段
createdAt DateTime @default(now())
account TradingAccount @relation(fields: [accountSequence], references: [accountSequence])
@@index([accountSequence, createdAt(sort: Desc)])
@@index([counterpartyAccountSeq])
@@index([counterpartyUserId])
@@map("trading_transactions")
}
// ==================== 流通池 ====================
// 流通池(交易所流通池)
model CirculationPool {
id String @id @default(uuid())
totalShares Decimal @default(0) @db.Decimal(30, 8) // 流通池中的积分股
totalCash Decimal @default(0) @db.Decimal(30, 8) // 流通池中的现金(股池)
totalInflow Decimal @default(0) @db.Decimal(30, 8) // 累计流入
totalOutflow Decimal @default(0) @db.Decimal(30, 8) // 累计流出
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
transactions CirculationPoolTransaction[]
@@map("circulation_pools")
}
// 流通池变动记录(包含交易对手方信息)
model CirculationPoolTransaction {
id String @id @default(uuid())
poolId String @map("pool_id")
type String // SHARE_IN, SHARE_OUT, CASH_IN, CASH_OUT, TRADE_BUY, TRADE_SELL
assetType String // SHARE, CASH
amount Decimal @db.Decimal(30, 8)
balanceBefore Decimal @map("balance_before") @db.Decimal(30, 8)
balanceAfter Decimal @map("balance_after") @db.Decimal(30, 8)
// 交易对手方信息关键用户ID和账户序列号
counterpartyType String? @map("counterparty_type") // USER, POOL, SYSTEM, EXTERNAL
counterpartyAccountSeq String? @map("counterparty_account_seq") // 对手方账户序列号
counterpartyUserId String? @map("counterparty_user_id") // 对手方用户ID
// 关联信息
referenceId String? @map("reference_id") // 关联业务ID如订单ID、交易ID
referenceType String? @map("reference_type") // 关联类型ORDER, TRADE, TRANSFER
// 详细备注(包含完整交易信息)
// 格式示例: "用户[U123456]买入100股, 订单号ORD20240110001"
memo String? @db.Text
// 扩展数据
metadata Json?
createdAt DateTime @default(now()) @map("created_at")
pool CirculationPool @relation(fields: [poolId], references: [id])
@@index([poolId, createdAt(sort: Desc)])
@@index([type, assetType])
@@index([counterpartyAccountSeq])
@@index([counterpartyUserId])
@@index([referenceId])
@@index([createdAt(sort: Desc)])
@@map("circulation_pool_transactions")
}
// 保留旧的PoolTransaction以兼容标记为废弃后续迁移后删除
// @deprecated 使用 CirculationPoolTransaction 替代
model PoolTransaction {
id String @id @default(uuid())
type String // SHARE_IN, SHARE_OUT, CASH_IN, CASH_OUT
amount Decimal @db.Decimal(30, 8)
referenceId String?
description String?
createdAt DateTime @default(now())
@@index([createdAt(sort: Desc)])
@@map("pool_transactions")
}
// ==================== K线数据 ====================
// 分钟K线
model MinuteKLine {
id String @id @default(uuid())
minute DateTime @unique
open Decimal @db.Decimal(30, 18)
high Decimal @db.Decimal(30, 18)
low Decimal @db.Decimal(30, 18)
close Decimal @db.Decimal(30, 18)
volume Decimal @db.Decimal(30, 8) // 成交量
amount Decimal @db.Decimal(30, 8) // 成交额
tradeCount Int @default(0) // 成交笔数
createdAt DateTime @default(now())
@@index([minute(sort: Desc)])
@@map("minute_klines")
}
// 小时K线
model HourKLine {
id String @id @default(uuid())
hour DateTime @unique
open Decimal @db.Decimal(30, 18)
high Decimal @db.Decimal(30, 18)
low Decimal @db.Decimal(30, 18)
close Decimal @db.Decimal(30, 18)
volume Decimal @db.Decimal(30, 8)
amount Decimal @db.Decimal(30, 8)
tradeCount Int @default(0)
createdAt DateTime @default(now())
@@index([hour(sort: Desc)])
@@map("hour_klines")
}
// 日K线
model DayKLine {
id String @id @default(uuid())
date DateTime @unique @db.Date
open Decimal @db.Decimal(30, 18)
high Decimal @db.Decimal(30, 18)
low Decimal @db.Decimal(30, 18)
close Decimal @db.Decimal(30, 18)
volume Decimal @db.Decimal(30, 8)
amount Decimal @db.Decimal(30, 8)
tradeCount Int @default(0)
createdAt DateTime @default(now())
@@index([date(sort: Desc)])
@@map("day_klines")
}
// ==================== 划转记录 ====================
// 从挖矿账户划转记录
model TransferRecord {
id String @id @default(uuid())
transferNo String @unique
accountSequence String
direction String // IN (从挖矿账户划入), OUT (划出到挖矿账户)
amount Decimal @db.Decimal(30, 8)
status String // PENDING, COMPLETED, FAILED
miningTxId String? // 挖矿服务的交易ID
errorMessage String?
createdAt DateTime @default(now())
completedAt DateTime?
@@index([accountSequence])
@@index([status])
@@map("transfer_records")
}
// ==================== Outbox ====================
enum OutboxStatus {
PENDING
PUBLISHED
FAILED
}
model OutboxEvent {
id String @id @default(uuid())
aggregateType String @map("aggregate_type")
aggregateId String @map("aggregate_id")
eventType String @map("event_type")
payload Json
topic String @default("trading.events")
key String?
status OutboxStatus @default(PENDING)
retryCount Int @default(0) @map("retry_count")
maxRetries Int @default(10) @map("max_retries")
lastError String? @map("last_error")
publishedAt DateTime? @map("published_at")
nextRetryAt DateTime? @map("next_retry_at")
createdAt DateTime @default(now()) @map("created_at")
@@index([status])
@@index([nextRetryAt])
@@index([createdAt])
@@map("outbox_events")
}