284 lines
9.5 KiB
Plaintext
284 lines
9.5 KiB
Plaintext
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")
|
||
}
|