refactor(trading): 价格数据源从 SharePool 切换到做市商 cashBalance
积分股价格公式中的"绿积分"(分子)本质上就是做市商的积分值余额, SharePool 是多余的抽象层。此次改动将价格计算的数据源从独立的 SharePool 表切换到做市商的 TradingAccount.cashBalance。 主要变更: - price.service.ts: 通过 PrismaService 直接读取做市商 cashBalance 作为价格公式的分子(绿积分),移除 SharePoolRepository 依赖 - asset.service.ts: getMarketOverview() 同步切换数据源 - order.service.ts: 10%交易手续费从 sharePoolRepository.feeIn() 改为 increment 回做市商的 TradingAccount,手续费自然留存在池中 - burn.service.ts: 移除 SharePool 初始化逻辑和依赖 - infrastructure.module.ts: 移除 SharePoolRepository 注册和导出 - seed.ts: 移除 SharePool 57.6亿初始化 价格公式、10%手续费扣除、销毁机制均保持不变,仅切换数据源。 SharePool 表和 repository 文件保留在磁盘上供历史数据参考。 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
14e70b56bb
commit
999d0389b3
|
|
@ -93,22 +93,7 @@ async function main() {
|
|||
console.log('Black hole account already exists');
|
||||
}
|
||||
|
||||
// 4. 初始化积分股池(绿积分池)
|
||||
// 初始绿积分为 57.6亿,使初始价格约为 0.576 (57.6亿 / 100.02亿 ≈ 0.576)
|
||||
const INITIAL_GREEN_POINTS = '5760000000'; // 57.6亿
|
||||
const existingSharePool = await prisma.sharePool.findFirst();
|
||||
if (!existingSharePool) {
|
||||
await prisma.sharePool.create({
|
||||
data: {
|
||||
greenPoints: new Decimal(INITIAL_GREEN_POINTS),
|
||||
totalInflow: new Decimal(INITIAL_GREEN_POINTS),
|
||||
totalOutflow: new Decimal(0),
|
||||
},
|
||||
});
|
||||
console.log(`Created share pool with initial green points: ${INITIAL_GREEN_POINTS} (57.6亿)`);
|
||||
} else {
|
||||
console.log('Share pool already exists');
|
||||
}
|
||||
// 4. 绿积分(价格分子)现在由做市商的 cashBalance 提供,不再需要独立的 SharePool
|
||||
|
||||
// 5. 初始化流通池
|
||||
const existingCirculationPool = await prisma.circulationPool.findFirst();
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { TradingCalculatorService } from '../../domain/services/trading-calculat
|
|||
import { TradingAccountRepository } from '../../infrastructure/persistence/repositories/trading-account.repository';
|
||||
import { BlackHoleRepository } from '../../infrastructure/persistence/repositories/black-hole.repository';
|
||||
import { CirculationPoolRepository } from '../../infrastructure/persistence/repositories/circulation-pool.repository';
|
||||
import { SharePoolRepository } from '../../infrastructure/persistence/repositories/share-pool.repository';
|
||||
import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service';
|
||||
import { PriceService } from './price.service';
|
||||
import { Money } from '../../domain/value-objects/money.vo';
|
||||
import Decimal from 'decimal.js';
|
||||
|
|
@ -59,11 +59,14 @@ export class AssetService {
|
|||
private readonly calculator = new TradingCalculatorService();
|
||||
private readonly miningServiceUrl: string;
|
||||
|
||||
// 缓存做市商 accountSequence
|
||||
private mmAccountSequence: string | null = null;
|
||||
|
||||
constructor(
|
||||
private readonly tradingAccountRepository: TradingAccountRepository,
|
||||
private readonly blackHoleRepository: BlackHoleRepository,
|
||||
private readonly circulationPoolRepository: CirculationPoolRepository,
|
||||
private readonly sharePoolRepository: SharePoolRepository,
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly priceService: PriceService,
|
||||
private readonly configService: ConfigService,
|
||||
) {
|
||||
|
|
@ -218,6 +221,24 @@ export class AssetService {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取做市商积分值余额(即价格公式中的"绿积分")
|
||||
*/
|
||||
private async getGreenPoints(): Promise<Money> {
|
||||
if (!this.mmAccountSequence) {
|
||||
const config = await this.prisma.marketMakerConfig.findUnique({
|
||||
where: { name: 'MAIN_MARKET_MAKER' },
|
||||
});
|
||||
this.mmAccountSequence = config?.accountSequence || null;
|
||||
}
|
||||
if (!this.mmAccountSequence) return Money.zero();
|
||||
|
||||
const account = await this.prisma.tradingAccount.findUnique({
|
||||
where: { accountSequence: this.mmAccountSequence },
|
||||
});
|
||||
return account ? new Money(account.cashBalance) : Money.zero();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取市场概览
|
||||
*/
|
||||
|
|
@ -232,13 +253,11 @@ export class AssetService {
|
|||
burnTarget: string;
|
||||
burnProgress: string;
|
||||
}> {
|
||||
const [sharePool, blackHole, circulationPool] = await Promise.all([
|
||||
this.sharePoolRepository.getPool(),
|
||||
const [greenPoints, blackHole, circulationPool] = await Promise.all([
|
||||
this.getGreenPoints(),
|
||||
this.blackHoleRepository.getBlackHole(),
|
||||
this.circulationPoolRepository.getPool(),
|
||||
]);
|
||||
|
||||
const greenPoints = sharePool?.greenPoints || Money.zero();
|
||||
const blackHoleAmount = blackHole?.totalBurned || Money.zero();
|
||||
const circulationPoolAmount = circulationPool?.totalShares || Money.zero();
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import { Injectable, Logger } from '@nestjs/common';
|
|||
import { TradingCalculatorService } from '../../domain/services/trading-calculator.service';
|
||||
import { BlackHoleRepository } from '../../infrastructure/persistence/repositories/black-hole.repository';
|
||||
import { CirculationPoolRepository } from '../../infrastructure/persistence/repositories/circulation-pool.repository';
|
||||
import { SharePoolRepository } from '../../infrastructure/persistence/repositories/share-pool.repository';
|
||||
import { TradingConfigRepository } from '../../infrastructure/persistence/repositories/trading-config.repository';
|
||||
import { OutboxRepository } from '../../infrastructure/persistence/repositories/outbox.repository';
|
||||
import { RedisService } from '../../infrastructure/redis/redis.service';
|
||||
|
|
@ -39,7 +38,6 @@ export class BurnService {
|
|||
constructor(
|
||||
private readonly blackHoleRepository: BlackHoleRepository,
|
||||
private readonly circulationPoolRepository: CirculationPoolRepository,
|
||||
private readonly sharePoolRepository: SharePoolRepository,
|
||||
private readonly tradingConfigRepository: TradingConfigRepository,
|
||||
private readonly outboxRepository: OutboxRepository,
|
||||
private readonly redis: RedisService,
|
||||
|
|
@ -243,11 +241,10 @@ export class BurnService {
|
|||
* 初始化交易系统(黑洞、配置、积分股池、流通池)
|
||||
*/
|
||||
async initialize(): Promise<void> {
|
||||
const [existingConfig, existingBlackHole, existingSharePool, existingCirculationPool] =
|
||||
const [existingConfig, existingBlackHole, existingCirculationPool] =
|
||||
await Promise.all([
|
||||
this.tradingConfigRepository.getConfig(),
|
||||
this.blackHoleRepository.getBlackHole(),
|
||||
this.sharePoolRepository.getPool(),
|
||||
this.circulationPoolRepository.getPool(),
|
||||
]);
|
||||
|
||||
|
|
@ -263,13 +260,7 @@ export class BurnService {
|
|||
this.logger.log('Black hole initialized');
|
||||
}
|
||||
|
||||
// 初始化积分股池(绿积分池),初始值 57.6亿
|
||||
// 使初始价格约为 0.576 (57.6亿 / 100.02亿 ≈ 0.576)
|
||||
if (!existingSharePool) {
|
||||
const initialGreenPoints = new Money('5760000000'); // 57.6亿
|
||||
await this.sharePoolRepository.initializePool(initialGreenPoints);
|
||||
this.logger.log(`Share pool initialized with ${initialGreenPoints.toFixed(8)} green points (57.6亿)`);
|
||||
}
|
||||
// 绿积分(价格分子)现在由做市商的 cashBalance 提供,不再需要独立的 SharePool
|
||||
|
||||
// 初始化流通池
|
||||
if (!existingCirculationPool) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import { Injectable, Logger } from '@nestjs/common';
|
|||
import { OrderRepository } from '../../infrastructure/persistence/repositories/order.repository';
|
||||
import { TradingAccountRepository } from '../../infrastructure/persistence/repositories/trading-account.repository';
|
||||
import { CirculationPoolRepository } from '../../infrastructure/persistence/repositories/circulation-pool.repository';
|
||||
import { SharePoolRepository } from '../../infrastructure/persistence/repositories/share-pool.repository';
|
||||
import { OutboxRepository } from '../../infrastructure/persistence/repositories/outbox.repository';
|
||||
import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service';
|
||||
import { RedisService } from '../../infrastructure/redis/redis.service';
|
||||
|
|
@ -32,7 +31,6 @@ export class OrderService {
|
|||
private readonly orderRepository: OrderRepository,
|
||||
private readonly accountRepository: TradingAccountRepository,
|
||||
private readonly circulationPoolRepository: CirculationPoolRepository,
|
||||
private readonly sharePoolRepository: SharePoolRepository,
|
||||
private readonly outboxRepository: OutboxRepository,
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly redis: RedisService,
|
||||
|
|
@ -338,21 +336,22 @@ export class OrderService {
|
|||
this.logger.warn(`Failed to add shares to circulation pool: ${error}`);
|
||||
}
|
||||
|
||||
// 10%手续费进入积分股池(非关键操作,可以在事务外执行)
|
||||
// 10%手续费存入做市商账户(做市商的 cashBalance 即积分股池的绿积分)
|
||||
try {
|
||||
await this.sharePoolRepository.feeIn(
|
||||
tradeFee,
|
||||
match.trade.tradeNo,
|
||||
match.buyOrder.accountSequence,
|
||||
match.sellOrder.accountSequence,
|
||||
match.buyOrder.source,
|
||||
match.sellOrder.source,
|
||||
);
|
||||
this.logger.debug(
|
||||
`Trade fee added to share pool: ${tradeFee.toFixed(8)}, tradeNo=${match.trade.tradeNo}`,
|
||||
);
|
||||
const mmConfig = await this.prisma.marketMakerConfig.findUnique({
|
||||
where: { name: 'MAIN_MARKET_MAKER' },
|
||||
});
|
||||
if (mmConfig) {
|
||||
await this.prisma.tradingAccount.update({
|
||||
where: { accountSequence: mmConfig.accountSequence },
|
||||
data: { cashBalance: { increment: tradeFee.value } },
|
||||
});
|
||||
this.logger.debug(
|
||||
`Trade fee deposited to market maker: ${tradeFee.toFixed(8)}, tradeNo=${match.trade.tradeNo}`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to add trade fee to share pool: ${error}`);
|
||||
this.logger.error(`Failed to deposit trade fee to market maker: ${error}`);
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { TradingCalculatorService } from '../../domain/services/trading-calculator.service';
|
||||
import { BlackHoleRepository } from '../../infrastructure/persistence/repositories/black-hole.repository';
|
||||
import { SharePoolRepository } from '../../infrastructure/persistence/repositories/share-pool.repository';
|
||||
import { CirculationPoolRepository } from '../../infrastructure/persistence/repositories/circulation-pool.repository';
|
||||
import { PriceSnapshotRepository } from '../../infrastructure/persistence/repositories/price-snapshot.repository';
|
||||
import { TradingConfigRepository } from '../../infrastructure/persistence/repositories/trading-config.repository';
|
||||
import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service';
|
||||
import { Money } from '../../domain/value-objects/money.vo';
|
||||
import Decimal from 'decimal.js';
|
||||
|
||||
|
|
@ -26,27 +26,47 @@ export class PriceService {
|
|||
private readonly logger = new Logger(PriceService.name);
|
||||
private readonly calculator = new TradingCalculatorService();
|
||||
|
||||
// 缓存做市商 accountSequence,避免每次查 MarketMakerConfig
|
||||
private mmAccountSequence: string | null = null;
|
||||
|
||||
constructor(
|
||||
private readonly blackHoleRepository: BlackHoleRepository,
|
||||
private readonly sharePoolRepository: SharePoolRepository,
|
||||
private readonly circulationPoolRepository: CirculationPoolRepository,
|
||||
private readonly priceSnapshotRepository: PriceSnapshotRepository,
|
||||
private readonly tradingConfigRepository: TradingConfigRepository,
|
||||
private readonly prisma: PrismaService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 获取做市商积分值余额(即价格公式中的"绿积分")
|
||||
* 做市商的 cashBalance 就是积分股池的绿积分
|
||||
*/
|
||||
private async getGreenPoints(): Promise<Money> {
|
||||
if (!this.mmAccountSequence) {
|
||||
const config = await this.prisma.marketMakerConfig.findUnique({
|
||||
where: { name: 'MAIN_MARKET_MAKER' },
|
||||
});
|
||||
this.mmAccountSequence = config?.accountSequence || null;
|
||||
}
|
||||
if (!this.mmAccountSequence) return Money.zero();
|
||||
|
||||
const account = await this.prisma.tradingAccount.findUnique({
|
||||
where: { accountSequence: this.mmAccountSequence },
|
||||
});
|
||||
return account ? new Money(account.cashBalance) : Money.zero();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前价格信息
|
||||
*/
|
||||
async getCurrentPrice(): Promise<PriceInfo> {
|
||||
const [sharePool, blackHole, circulationPool, config, firstSnapshot] = await Promise.all([
|
||||
this.sharePoolRepository.getPool(),
|
||||
const [greenPoints, blackHole, circulationPool, config, firstSnapshot] = await Promise.all([
|
||||
this.getGreenPoints(),
|
||||
this.blackHoleRepository.getBlackHole(),
|
||||
this.circulationPoolRepository.getPool(),
|
||||
this.tradingConfigRepository.getConfig(),
|
||||
this.priceSnapshotRepository.getFirstSnapshot(),
|
||||
]);
|
||||
|
||||
const greenPoints = sharePool?.greenPoints || Money.zero();
|
||||
const blackHoleAmount = blackHole?.totalBurned || Money.zero();
|
||||
const circulationPoolAmount = circulationPool?.totalShares || Money.zero();
|
||||
|
||||
|
|
@ -152,14 +172,12 @@ export class PriceService {
|
|||
*/
|
||||
async createSnapshot(): Promise<void> {
|
||||
try {
|
||||
const [sharePool, blackHole, circulationPool, config] = await Promise.all([
|
||||
this.sharePoolRepository.getPool(),
|
||||
const [greenPoints, blackHole, circulationPool, config] = await Promise.all([
|
||||
this.getGreenPoints(),
|
||||
this.blackHoleRepository.getBlackHole(),
|
||||
this.circulationPoolRepository.getPool(),
|
||||
this.tradingConfigRepository.getConfig(),
|
||||
]);
|
||||
|
||||
const greenPoints = sharePool?.greenPoints || Money.zero();
|
||||
const blackHoleAmount = blackHole?.totalBurned || Money.zero();
|
||||
const circulationPoolAmount = circulationPool?.totalShares || Money.zero();
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import { OrderRepository } from './persistence/repositories/order.repository';
|
|||
import { OutboxRepository } from './persistence/repositories/outbox.repository';
|
||||
import { TradingConfigRepository } from './persistence/repositories/trading-config.repository';
|
||||
import { BlackHoleRepository } from './persistence/repositories/black-hole.repository';
|
||||
import { SharePoolRepository } from './persistence/repositories/share-pool.repository';
|
||||
import { CirculationPoolRepository } from './persistence/repositories/circulation-pool.repository';
|
||||
import { PriceSnapshotRepository } from './persistence/repositories/price-snapshot.repository';
|
||||
import { ProcessedEventRepository } from './persistence/repositories/processed-event.repository';
|
||||
|
|
@ -53,7 +52,6 @@ import { IdentityClient } from './identity/identity.client';
|
|||
OutboxRepository,
|
||||
TradingConfigRepository,
|
||||
BlackHoleRepository,
|
||||
SharePoolRepository,
|
||||
CirculationPoolRepository,
|
||||
PriceSnapshotRepository,
|
||||
ProcessedEventRepository,
|
||||
|
|
@ -81,7 +79,6 @@ import { IdentityClient } from './identity/identity.client';
|
|||
OutboxRepository,
|
||||
TradingConfigRepository,
|
||||
BlackHoleRepository,
|
||||
SharePoolRepository,
|
||||
CirculationPoolRepository,
|
||||
PriceSnapshotRepository,
|
||||
ProcessedEventRepository,
|
||||
|
|
|
|||
Loading…
Reference in New Issue