1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888 |
- #!/usr/bin/env tsx
- /**
- * 简洁版Delta中性刷量策略
- * 只显示关键信息,日志简洁清晰
- */
- import { DeltaNeutralVolumeStrategy, DeltaNeutralConfig } from '../src/strategies/DeltaNeutralVolumeStrategy';
- import { DeltaNeutralConfigManager } from '../src/strategies/DeltaNeutralConfig';
- import { PacificaSigningClient } from '../src/services/PacificaSigningClient';
- import { RiskManager, RiskManagerConfig } from '../src/core/RiskManager';
- import { MarketDataManager } from '../src/services/MarketDataManager';
- import { OrderCleanupService, CleanupOptions } from '../src/services/OrderCleanupService';
- import { DynamicPositionManager, PositionAdjustmentConfig } from '../src/services/DynamicPositionManager';
- import { Account } from '../src/models/Account';
- import { readFileSync, writeFileSync, existsSync } from 'fs';
- import { v4 as uuidv4 } from 'uuid';
- interface OrderLifecycle {
- orderId: string;
- clientOrderId: string;
- accountId: string; // 记录创建订单的账户ID
- symbol: string;
- side: 'bid' | 'ask';
- amount: string;
- price: string;
- status: 'pending' | 'filled' | 'cancelled' | 'expired';
- createdAt: number;
- lastChecked: number;
- checkCount: number;
- maxChecks: number;
- }
- interface SimpleStats {
- totalOrders: number;
- filledOrders: number;
- cancelledOrders: number;
- expiredOrders: number;
- totalVolume: number;
- totalPnL: number;
- startTime: number;
- lastUpdateTime: number;
- consecutiveErrors: number;
- maxConsecutiveErrors: number;
- apiCallCount: number;
- lastApiError: number;
- lastSuccessfulTrade: number;
- retryCount: number;
- totalRetries: number;
- }
- class SimpleDeltaNeutralStrategy extends DeltaNeutralVolumeStrategy {
- private orderLifecycle: Map<string, OrderLifecycle> = new Map();
- private lastApiCall: number = 0;
- private apiCallInterval: number = 2000; // 2秒间隔
- private orderCheckInterval: NodeJS.Timeout | null = null;
- private volumeTradingInterval: NodeJS.Timeout | null = null;
- private deltaMonitoringInterval: NodeJS.Timeout | null = null;
- private statusDisplayInterval: NodeJS.Timeout | null = null;
- private statsSaveInterval: NodeJS.Timeout | null = null;
- private healthCheckInterval: NodeJS.Timeout | null = null;
- // 账户配对 - Delta中性核心机制
- private accountPairs: Array<[Account, Account]> = [];
- // 多账户客户端映射 - 每个账户一个客户端
- private clientMap: Map<string, PacificaSigningClient> = new Map();
- // 账户列表(保存引用用于动态仓位管理)
- private strategyAccounts: Account[] = [];
- // 风险管理器
- private riskManager: RiskManager | null = null;
- private sessionId: string;
- // 市场数据管理器 - WebSocket实时行情
- private marketDataManager: MarketDataManager | null = null;
- private currentBTCPrice: number = 0;
- private isPriceReady: boolean = false;
- // 动态仓位管理器 - 保证金使用率过高时自动减仓
- private dynamicPositionManager: DynamicPositionManager | null = null;
- // 简洁版统计信息
- private stats: SimpleStats = {
- totalOrders: 0,
- filledOrders: 0,
- cancelledOrders: 0,
- expiredOrders: 0,
- totalVolume: 0,
- totalPnL: 0,
- startTime: Date.now(),
- lastUpdateTime: Date.now(),
- consecutiveErrors: 0,
- maxConsecutiveErrors: 3,
- apiCallCount: 0,
- lastApiError: 0,
- lastSuccessfulTrade: 0,
- retryCount: 0,
- totalRetries: 0
- };
- // 配置参数
- private readonly STATS_SAVE_INTERVAL = 600000; // 10分钟保存一次统计
- private readonly HEALTH_CHECK_INTERVAL = 300000; // 5分钟健康检查
- private readonly MAX_RUNTIME = 6 * 60 * 60 * 1000; // 6小时最大运行时间
- private readonly ERROR_RECOVERY_DELAY = 60000; // 60秒错误恢复延迟
- private readonly STATS_FILE = './data/simple-stats.json';
- private readonly TRADING_PAUSE_DURATION = 120000; // 120秒交易暂停
- private readonly MAX_RETRY_ATTEMPTS = 2; // 最大重试次数
- private readonly RETRY_DELAY = 10000; // 重试延迟
- // 状态控制
- private isTradingPaused = false;
- private lastTradingPause = 0;
- private isInitialized = false;
- constructor(
- config: DeltaNeutralConfig,
- pacificaClient: PacificaSigningClient,
- accounts: Account[]
- ) {
- super(config, pacificaClient, accounts);
- this.sessionId = `session_${Date.now()}`;
- this.strategyAccounts = accounts; // 保存账户引用
- // 为每个账户创建独立的客户端
- accounts.forEach(account => {
- const client = new PacificaSigningClient(account.getPrivateKey());
- this.clientMap.set(account.getId(), client);
- });
- this.loadStats();
- this.initializeRiskManager(config);
- this.initializeMarketDataManager();
- this.initializeDynamicPositionManager();
- }
- /**
- * 初始化风险管理器
- */
- private initializeRiskManager(config: DeltaNeutralConfig): void {
- const riskConfig: RiskManagerConfig = {
- maxTotalVolume: config.maxVolumePositionSize * 10, // 最大总量
- maxNetExposure: config.maxDeltaDeviation, // 最大净敞口
- maxDailyLoss: config.stopLossThreshold, // 最大每日亏损
- positionLimit: config.maxVolumePositionSize, // 仓位限制
- stopLossThreshold: config.stopLossThreshold, // 止损阈值
- monitoringInterval: 60000 // 60秒监控间隔
- };
- this.riskManager = new RiskManager(riskConfig);
- this.riskManager.on('breach_detected', (breach) => {
- this.log(`风险告警: ${breach.type} - ${breach.severity}`, 'error');
- if (breach.severity === 'critical') {
- this.pauseTrading();
- }
- });
- }
- /**
- * 初始化市场数据管理器
- * 使用WebSocket订阅实时行情,替代REST轮询
- */
- private initializeMarketDataManager(): void {
- this.marketDataManager = new MarketDataManager();
- // 监听实时价格更新
- this.marketDataManager.on('price_update', (priceData) => {
- if (priceData.symbol === 'BTC') {
- this.currentBTCPrice = parseFloat(priceData.mark);
- if (!this.isPriceReady) {
- this.isPriceReady = true;
- this.log(`BTC实时价格已就绪: $${this.currentBTCPrice.toFixed(2)}`, 'success');
- }
- }
- });
- // 监听WebSocket连接状态
- this.marketDataManager.on('connected', () => {
- this.log('WebSocket市场数据已连接', 'success');
- });
- this.marketDataManager.on('disconnected', () => {
- this.log('WebSocket市场数据断开,切换到REST轮询', 'warning');
- this.isPriceReady = false;
- });
- }
- /**
- * 初始化动态仓位管理器
- * 当保证金使用率过高时自动减仓
- */
- private initializeDynamicPositionManager(): void {
- // 从配置文件读取设置
- let config: PositionAdjustmentConfig;
- try {
- const strategyConfig = JSON.parse(readFileSync('./config/trading-strategy.json', 'utf-8'));
- const posConfig = strategyConfig.dynamicPositionAdjustment;
- config = {
- enabled: posConfig.enabled ?? true,
- maxMarginUsageThreshold: posConfig.maxMarginUsageThreshold ?? 0.85,
- targetMarginRelease: posConfig.targetMarginRelease ?? 0.2,
- minPositionRatio: posConfig.minPositionRatio ?? 0.3,
- checkInterval: posConfig.checkInterval ?? 10000
- };
- } catch (error) {
- // 使用默认配置
- config = {
- enabled: true,
- maxMarginUsageThreshold: 0.85,
- targetMarginRelease: 0.2,
- minPositionRatio: 0.3,
- checkInterval: 10000
- };
- }
- this.dynamicPositionManager = new DynamicPositionManager(config);
- this.log('动态仓位管理器已初始化', 'success');
- }
- /**
- * 简洁版日志输出
- */
- private log(message: string, type: 'info' | 'success' | 'warning' | 'error' = 'info'): void {
- const icons = {
- info: '📊',
- success: '✅',
- warning: '⚠️',
- error: '❌'
- };
- // 只显示重要信息,减少时间戳
- if (type === 'error' || type === 'success') {
- console.log(`${icons[type]} ${message}`);
- }
- }
- /**
- * 加载统计信息
- */
- private loadStats(): void {
- try {
- if (existsSync(this.STATS_FILE)) {
- const savedStats = JSON.parse(readFileSync(this.STATS_FILE, 'utf-8'));
- this.stats = { ...this.stats, ...savedStats };
- this.log(`加载历史统计: 运行${Math.floor((Date.now() - this.stats.startTime) / 1000 / 60)}分钟`, 'info');
- }
- } catch (error) {
- // 静默处理加载错误
- }
- }
- /**
- * 保存统计信息
- */
- private saveStats(): void {
- try {
- this.stats.lastUpdateTime = Date.now();
- writeFileSync(this.STATS_FILE, JSON.stringify(this.stats, null, 2));
- } catch (error) {
- // 静默处理保存错误
- }
- }
- /**
- * 带重试的API调用
- */
- private async callApiWithRetry<T>(
- apiCall: () => Promise<T>,
- operation: string,
- maxRetries: number = this.MAX_RETRY_ATTEMPTS
- ): Promise<T> {
- let lastError: Error | null = null;
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
- try {
- await this.waitForApiCallInterval();
- const result = await apiCall();
- this.stats.apiCallCount++;
- this.stats.retryCount = 0;
- return result;
- } catch (error) {
- lastError = error as Error;
- this.stats.retryCount++;
- this.stats.totalRetries++;
- if (attempt < maxRetries) {
- const delay = this.RETRY_DELAY * attempt;
- await new Promise(resolve => setTimeout(resolve, delay));
- }
- }
- }
- throw lastError;
- }
- /**
- * 健康检查
- */
- private async performHealthCheck(): Promise<void> {
- try {
- const runtime = Date.now() - this.stats.startTime;
- // 检查最大运行时间
- if (runtime > this.MAX_RUNTIME) {
- this.log(`达到最大运行时间,准备停止`, 'warning');
- await this.stop();
- process.exit(0);
- }
- // 检查连续错误
- if (this.stats.consecutiveErrors >= this.stats.maxConsecutiveErrors) {
- this.log(`连续错误过多,暂停交易`, 'error');
- await this.pauseTrading();
- return;
- }
- // 检查API连接
- await this.callApiWithRetry(
- () => this.pacificaClient.getPrices(),
- '健康检查API连接'
- );
- // 重置连续错误计数
- if (this.stats.consecutiveErrors > 0) {
- this.stats.consecutiveErrors = 0;
- this.log('API连接恢复', 'success');
- }
- // 检查交易暂停状态
- if (this.isTradingPaused && Date.now() - this.lastTradingPause > this.TRADING_PAUSE_DURATION) {
- this.log('恢复交易', 'info');
- this.isTradingPaused = false;
- }
- } catch (error) {
- this.stats.consecutiveErrors++;
- this.stats.lastApiError = Date.now();
- this.log(`健康检查失败`, 'error');
- }
- }
- /**
- * 暂停交易
- */
- private async pauseTrading(): Promise<void> {
- this.log('暂停交易,等待错误恢复...', 'warning');
- this.isTradingPaused = true;
- this.lastTradingPause = Date.now();
- // 暂停交易定时器
- if (this.volumeTradingInterval) {
- clearInterval(this.volumeTradingInterval);
- this.volumeTradingInterval = null;
- }
- // 等待错误恢复
- setTimeout(async () => {
- this.log('尝试恢复交易...', 'info');
- await this.resumeTrading();
- }, this.ERROR_RECOVERY_DELAY);
- }
- /**
- * 恢复交易
- */
- private async resumeTrading(): Promise<void> {
- try {
- // 重新检查API连接
- await this.callApiWithRetry(
- () => this.pacificaClient.getPrices(),
- '恢复交易API检查'
- );
- // 恢复交易定时器
- this.startVolumeTrading();
- this.log('交易恢复成功', 'success');
- } catch (error) {
- this.log(`交易恢复失败`, 'error');
- await this.pauseTrading();
- }
- }
- /**
- * 重写开始刷量交易方法
- */
- protected async startVolumeTrading(): Promise<void> {
- this.log('启动简洁版刷量交易系统', 'info');
- // 启动订单生命周期管理
- this.startOrderLifecycleManagement();
- // 启动状态显示
- this.startStatusDisplay();
- // 启动统计保存
- this.startStatsSaving();
- // 启动健康检查
- this.startHealthCheck();
- // 启动动态仓位管理
- await this.startDynamicPositionManager();
- // 刷量交易 - 15秒间隔
- this.volumeTradingInterval = setInterval(async () => {
- try {
- if (!this.isTradingPaused && this.isInitialized) {
- await this.executeVolumeTradingCycle();
- }
- } catch (error) {
- this.stats.consecutiveErrors++;
- this.log(`刷量交易失败`, 'warning');
- }
- }, 15000); // 15秒间隔
- // Delta监控 - 120秒间隔
- this.deltaMonitoringInterval = setInterval(async () => {
- try {
- if (this.isInitialized) {
- await this.monitorAndRebalance();
- }
- } catch (error) {
- this.stats.consecutiveErrors++;
- this.log(`Delta监控失败`, 'warning');
- }
- }, 120000); // 120秒间隔
- }
- /**
- * 启动订单生命周期管理
- */
- private startOrderLifecycleManagement(): void {
- this.orderCheckInterval = setInterval(async () => {
- try {
- await this.checkOrderLifecycle();
- } catch (error) {
- this.stats.consecutiveErrors++;
- this.log(`订单检查失败`, 'warning');
- }
- }, 60000); // 60秒检查一次
- }
- /**
- * 启动状态显示
- */
- private startStatusDisplay(): void {
- this.statusDisplayInterval = setInterval(() => {
- this.displayStatus();
- }, 600000); // 每10分钟显示一次
- }
- /**
- * 启动统计保存
- */
- private startStatsSaving(): void {
- this.statsSaveInterval = setInterval(() => {
- this.saveStats();
- }, this.STATS_SAVE_INTERVAL);
- }
- /**
- * 启动健康检查
- */
- private startHealthCheck(): void {
- this.healthCheckInterval = setInterval(async () => {
- await this.performHealthCheck();
- }, this.HEALTH_CHECK_INTERVAL);
- }
- /**
- * 启动动态仓位管理器
- */
- private async startDynamicPositionManager(): Promise<void> {
- if (!this.dynamicPositionManager) {
- console.log('⚠️ 动态仓位管理器未初始化');
- return;
- }
- // 为每个账户初始化管理器
- for (const account of this.strategyAccounts) {
- const client = this.clientMap.get(account.getId());
- if (client) {
- this.dynamicPositionManager.initializeAccount(account, client);
- console.log(`✅ 为账户 ${account.getName()} 初始化动态仓位管理`);
- }
- }
- // 启动监控
- await this.dynamicPositionManager.startMonitoring(this.strategyAccounts);
- console.log('✅ 动态仓位管理监控已启动');
- this.log('动态仓位管理监控已启动', 'success');
- }
- /**
- * 显示策略状态
- */
- private displayStatus(): void {
- const runtime = Math.floor((Date.now() - this.stats.startTime) / 1000);
- const runtimeStr = `${Math.floor(runtime / 3600)}时${Math.floor((runtime % 3600) / 60)}分${runtime % 60}秒`;
- console.log('\n' + '='.repeat(50));
- console.log('📈 简洁版策略运行状态');
- console.log('='.repeat(50));
- console.log(`⏰ 运行时间: ${runtimeStr}`);
- console.log(`📊 总订单数: ${this.stats.totalOrders}`);
- console.log(`✅ 已成交: ${this.stats.filledOrders}`);
- console.log(`❌ 已取消: ${this.stats.cancelledOrders}`);
- console.log(`📈 总交易量: ${this.stats.totalVolume.toFixed(6)} BTC`);
- console.log(`💰 总PNL: ${this.stats.totalPnL.toFixed(2)} USDC`);
- console.log(`🔄 活跃订单: ${this.orderLifecycle.size}`);
- console.log(`🌐 API调用: ${this.stats.apiCallCount}`);
- console.log(`⚠️ 连续错误: ${this.stats.consecutiveErrors}`);
- console.log(`⏸️ 交易状态: ${this.isTradingPaused ? '暂停' : '正常'}`);
- // 显示WebSocket价格状态
- if (this.isPriceReady) {
- console.log(`💹 BTC价格: $${this.currentBTCPrice.toFixed(2)} (WebSocket实时)`);
- } else {
- console.log(`💹 价格源: REST API (WebSocket未就绪)`);
- }
- // 显示账户配对信息
- console.log(`🔗 账户配对: ${this.accountPairs.length}对`);
- if (this.stats.totalOrders > 0) {
- const successRate = ((this.stats.filledOrders / this.stats.totalOrders) * 100).toFixed(1);
- console.log(`🎯 成交率: ${successRate}%`);
- }
- // 显示健康状态
- const healthStatus = this.stats.consecutiveErrors === 0 ? '🟢 健康' : '🔴 异常';
- console.log(`🏥 健康状态: ${healthStatus}`);
- console.log('='.repeat(50) + '\n');
- }
- /**
- * 检查订单生命周期
- */
- private async checkOrderLifecycle(): Promise<void> {
- const now = Date.now();
- const ordersToRemove: string[] = [];
- for (const [orderId, order] of this.orderLifecycle) {
- try {
- // 检查订单是否超时
- const timeSinceCreated = now - order.createdAt;
- const maxOrderLifetime = 600000; // 600秒最大生命周期
- if (timeSinceCreated > maxOrderLifetime) {
- this.log(`订单超时取消: ${orderId}`, 'warning');
- await this.cancelOrderSafely(orderId, order.symbol);
- this.stats.cancelledOrders++;
- ordersToRemove.push(orderId);
- continue;
- }
- // 检查订单状态
- if (order.status === 'pending' && order.checkCount < order.maxChecks) {
- await this.checkOrderStatus(order);
- order.checkCount++;
- order.lastChecked = now;
- }
- // 如果检查次数过多,标记为过期
- if (order.checkCount >= order.maxChecks) {
- this.log(`订单检查超限: ${orderId}`, 'warning');
- order.status = 'expired';
- this.stats.expiredOrders++;
- ordersToRemove.push(orderId);
- }
- } catch (error) {
- this.log(`检查订单失败: ${orderId}`, 'error');
- ordersToRemove.push(orderId);
- }
- }
- // 清理过期订单
- for (const orderId of ordersToRemove) {
- this.orderLifecycle.delete(orderId);
- }
- }
- /**
- * 检查单个订单状态
- */
- private async checkOrderStatus(order: OrderLifecycle): Promise<void> {
- try {
- const openOrdersResponse = await this.callApiWithRetry(
- () => this.pacificaClient.getOpenOrders(),
- '检查订单状态'
- );
- const openOrders = Array.isArray(openOrdersResponse) ? openOrdersResponse : openOrdersResponse.data || [];
- const orderExists = openOrders.some((o: any) => o.order_id === parseInt(order.orderId));
- if (!orderExists) {
- order.status = 'filled';
- this.stats.filledOrders++;
- this.stats.totalVolume += parseFloat(order.amount);
- this.stats.lastSuccessfulTrade = Date.now();
- this.log(`订单成交: ${order.side.toUpperCase()} ${order.amount} BTC @ ${order.price}`, 'success');
- }
- } catch (error) {
- this.log(`检查订单状态失败: ${order.orderId}`, 'error');
- }
- }
- /**
- * 安全取消订单
- */
- private async cancelOrderSafely(orderId: string, symbol: string): Promise<void> {
- try {
- await this.callApiWithRetry(
- () => this.pacificaClient.cancelOrder(orderId, symbol),
- `取消订单 ${orderId}`
- );
- } catch (error) {
- this.log(`取消订单失败: ${orderId}`, 'error');
- }
- }
- /**
- * API调用间隔控制
- */
- private async waitForApiCallInterval(): Promise<void> {
- const now = Date.now();
- const timeSinceLastCall = now - this.lastApiCall;
- if (timeSinceLastCall < this.apiCallInterval) {
- const waitTime = this.apiCallInterval - timeSinceLastCall;
- await new Promise(resolve => setTimeout(resolve, waitTime));
- }
- this.lastApiCall = Date.now();
- }
- /**
- * 重写刷量交易执行
- * 优先使用WebSocket实时价格,如果不可用则回退到REST API
- */
- protected async executeVolumeTrades(): Promise<void> {
- try {
- // 检查是否应该暂停交易
- if (this.isTradingPaused || !this.isInitialized) {
- return;
- }
- let currentPrice: number;
- // 优先使用WebSocket实时价格
- if (this.isPriceReady && this.currentBTCPrice > 0) {
- currentPrice = this.currentBTCPrice;
- // 无需API调用,直接使用缓存的实时价格
- } else {
- // 回退到REST API
- this.log('使用REST API获取价格 (WebSocket未就绪)', 'warning');
- const prices = await this.callApiWithRetry(
- () => this.pacificaClient.getPrices(),
- '获取价格信息'
- );
- const btcPrice = prices.data.find((p: any) => p.symbol === 'BTC');
- currentPrice = parseFloat(btcPrice.mark);
- }
- const totalAccountValue = await this.getTotalAccountValue();
- const volumePositionSize = Math.min(
- this.config.maxVolumePositionSize,
- this.config.volumePositionRatio * totalAccountValue / currentPrice
- );
- // 使用账户配对执行Delta中性刷量
- // 每对账户: 一个买入, 一个卖出, 保证净仓位为零
- for (const [buyAccount, sellAccount] of this.accountPairs) {
- await this.executePairedVolumeTrade(
- buyAccount,
- sellAccount,
- volumePositionSize,
- currentPrice
- );
- }
- } catch (error) {
- this.log(`刷量交易失败`, 'warning');
- }
- }
- /**
- * 执行配对刷量交易
- * 确保买入和卖出同步执行,保持Delta中性
- */
- private async executePairedVolumeTrade(
- buyAccount: Account,
- sellAccount: Account,
- volumePositionSize: number,
- currentPrice: number
- ): Promise<void> {
- try {
- // 计算交易数量 - 满足$10最低订单价值要求
- const LOT_SIZE = 0.00001; // BTC最小订单大小 (lot size)
- const MIN_ORDER_VALUE = 10; // $10 USDC最低订单价值
- // 计算满足$10最低要求的BTC数量
- const minBtcAmount = MIN_ORDER_VALUE / currentPrice;
- const MIN_ORDER_SIZE = Math.ceil(minBtcAmount / LOT_SIZE) * LOT_SIZE;
- let tradeSize = Math.max(
- MIN_ORDER_SIZE,
- Math.min(
- volumePositionSize * 0.5, // 每次交易50%的刷量仓位
- this.config.maxVolumePositionSize // 最大刷量仓位
- )
- );
- // 确保是lot size的整数倍
- tradeSize = Math.floor(tradeSize / LOT_SIZE) * LOT_SIZE;
- tradeSize = Math.max(tradeSize, MIN_ORDER_SIZE);
- // 验证订单价值
- const orderValue = tradeSize * currentPrice;
- if (orderValue < MIN_ORDER_VALUE) {
- this.log(`订单价值过低: $${orderValue.toFixed(2)} < $10, 跳过`, 'warning');
- return;
- }
- // 余额检查
- const buyClient = this.clientMap.get(buyAccount.getId());
- const sellClient = this.clientMap.get(sellAccount.getId());
- if (!buyClient || !sellClient) {
- this.log('账户客户端未找到,跳过交易', 'warning');
- return;
- }
- // 检查买入账户余额
- const buyBalance = await this.checkAccountBalance(buyAccount, buyClient, orderValue);
- if (!buyBalance) {
- this.log(`买入账户余额不足: ${buyAccount.getId().slice(0,8)}`, 'warning');
- this.handleInsufficientBalance();
- return;
- }
- // 检查卖出账户是否有足够的BTC
- const sellBalance = await this.checkAccountBalance(sellAccount, sellClient, tradeSize, true);
- if (!sellBalance) {
- this.log(`卖出账户BTC不足: ${sellAccount.getId().slice(0,8)}`, 'warning');
- this.handleInsufficientBalance();
- return;
- }
- // 风险检查 - 在执行交易前检查仓位大小
- if (this.riskManager) {
- const buyRiskBreach = await this.riskManager.checkPositionSizeRisk(
- this.sessionId,
- buyAccount.getId(),
- tradeSize
- );
- const sellRiskBreach = await this.riskManager.checkPositionSizeRisk(
- this.sessionId,
- sellAccount.getId(),
- tradeSize
- );
- if (buyRiskBreach || sellRiskBreach) {
- this.log(`风险检查未通过,跳过本次交易`, 'warning');
- return;
- }
- }
- // 同步执行买入和卖出订单 - 这是Delta中性的关键
- await Promise.all([
- this.executeAccountVolumeTradeWithLifecycle(buyAccount, tradeSize, currentPrice, 'bid'),
- this.executeAccountVolumeTradeWithLifecycle(sellAccount, tradeSize, currentPrice, 'ask')
- ]);
- this.log(`配对交易: ${buyAccount.getId().slice(0,8)}买/${sellAccount.getId().slice(0,8)}卖`, 'success');
- } catch (error) {
- this.log(`配对交易失败: ${buyAccount.getId().slice(0,8)} <-> ${sellAccount.getId().slice(0,8)}`, 'warning');
- }
- }
- /**
- * 带生命周期管理的账户刷量交易
- * @param side - 'bid' (买入) 或 'ask' (卖出), 由配对机制指定
- */
- private async executeAccountVolumeTradeWithLifecycle(
- account: Account,
- tradeSize: number,
- currentPrice: number,
- side: 'bid' | 'ask'
- ): Promise<void> {
- try {
- // 获取账户专属客户端
- const client = this.clientMap.get(account.getId());
- if (!client) {
- this.log(`账户客户端未找到: ${account.getId()}`, 'error');
- return;
- }
- // 智能选择订单类型
- if (this.config.preferredOrderType === 'limit') {
- await this.createLimitOrderWithLifecycle(account, client, side, tradeSize, currentPrice);
- } else {
- await this.createVolumeMarketOrder(account, client, side, tradeSize);
- }
- } catch (error) {
- this.log(`账户交易失败: ${account.getId()} (${side})`, 'warning');
- }
- }
- /**
- * 创建带生命周期管理的limit订单(优先限价单降低手续费)
- */
- private async createLimitOrderWithLifecycle(
- account: Account,
- client: PacificaSigningClient,
- side: 'bid' | 'ask',
- amount: number,
- currentPrice: number
- ): Promise<void> {
- try {
- // 使用更小的价差提高成交率
- const spread = this.config.limitOrderSpread;
- const price = side === 'bid'
- ? (currentPrice * (1 - spread)).toFixed(0)
- : (currentPrice * (1 + spread)).toFixed(0);
- const clientOrderId = uuidv4();
- const order = {
- symbol: 'BTC',
- amount: amount.toFixed(8),
- side,
- price,
- tif: 'GTC', // Good-Till-Cancel (挂单等待成交)
- reduce_only: false,
- client_order_id: clientOrderId
- };
- const result = await this.callApiWithRetry(
- () => client.createLimitOrder(order),
- `创建${side}订单 (${account.getId().slice(0,8)})`
- );
- if (result.success && result.data?.order_id) {
- const orderId = result.data.order_id.toString();
- // 创建订单生命周期记录 - 10秒超时
- const orderLifecycle: OrderLifecycle = {
- orderId,
- clientOrderId,
- accountId: account.getId(), // 记录账户ID
- symbol: 'BTC',
- side,
- amount: order.amount,
- price: order.price,
- status: 'pending',
- createdAt: Date.now(),
- lastChecked: Date.now(),
- checkCount: 0,
- maxChecks: 1 // 10秒超时(检查1次后转市价单)
- };
- this.orderLifecycle.set(orderId, orderLifecycle);
- this.stats.totalOrders++;
- this.log(`限价单: ${side.toUpperCase()} ${amount.toFixed(6)} BTC @ $${price} (${account.getId().slice(0,8)})`, 'info');
- // 启动订单监控(如果还未启动)
- if (!this.orderCheckInterval) {
- this.startOrderMonitoring();
- }
- }
- } catch (error) {
- this.log(`限价单失败: ${side}, 降级为市价单`, 'warning');
- // 限价单失败,降级为市价单
- await this.createVolumeMarketOrder(account, client, side, amount);
- }
- }
- /**
- * 启动订单状态监控
- */
- private startOrderMonitoring(): void {
- this.orderCheckInterval = setInterval(async () => {
- await this.checkPendingOrders();
- }, 10000); // 每10秒检查一次
- this.log('订单监控已启动 (10秒间隔)', 'info');
- }
- /**
- * 检查待处理订单状态
- */
- private async checkPendingOrders(): Promise<void> {
- const now = Date.now();
- const ordersToCheck = Array.from(this.orderLifecycle.entries())
- .filter(([_, order]) => order.status === 'pending');
- for (const [orderId, order] of ordersToCheck) {
- try {
- order.checkCount++;
- order.lastChecked = now;
- // 检查是否超时
- const ageSeconds = (now - order.createdAt) / 1000;
- if (order.checkCount >= order.maxChecks) {
- // 超时未成交,撤单并使用市价单重试
- this.log(`限价单超时 (${ageSeconds.toFixed(0)}s): ${order.side.toUpperCase()} @ $${order.price}, 转市价单`, 'warning');
- await this.cancelAndRetryWithMarket(orderId, order);
- }
- } catch (error) {
- this.log(`检查订单${orderId}失败`, 'warning');
- }
- }
- }
- /**
- * 撤单并使用市价单重试
- */
- private async cancelAndRetryWithMarket(orderId: string, order: OrderLifecycle): Promise<void> {
- try {
- // 使用订单记录中的账户ID找到正确的账户和客户端
- const targetAccount = this.accounts.find(acc => acc.getId() === order.accountId);
- const targetClient = targetAccount ? this.clientMap.get(targetAccount.getId()) : null;
- if (!targetAccount || !targetClient) {
- this.log(`找不到订单对应的账户: ${order.accountId.slice(0,8)}`, 'error');
- return;
- }
- // 尝试撤销订单
- try {
- await targetClient.cancelOrder(orderId, 'BTC');
- this.log(`已撤销限价单: ${orderId} (${targetAccount.getId().slice(0,8)})`, 'info');
- } catch (error) {
- // 订单可能已成交或不存在,忽略错误
- this.log(`撤单失败(可能已成交): ${orderId}`, 'warning');
- }
- // 标记为已取消
- order.status = 'cancelled';
- this.stats.cancelledOrders++;
- // 使用市价单重试相同数量
- const amount = parseFloat(order.amount);
- this.log(`市价单重试: ${order.side.toUpperCase()} ${amount.toFixed(6)} BTC (${targetAccount.getId().slice(0,8)})`, 'info');
- await this.createVolumeMarketOrder(
- targetAccount,
- targetClient,
- order.side,
- amount
- );
- } catch (error) {
- this.log(`撤单重试失败: ${orderId}`, 'error');
- }
- }
- /**
- * 创建市场订单
- */
- private async createVolumeMarketOrder(
- account: Account,
- client: PacificaSigningClient,
- side: 'bid' | 'ask',
- amount: number
- ): Promise<void> {
- try {
- const clientOrderId = uuidv4();
- const order = {
- symbol: 'BTC',
- amount: amount.toFixed(8),
- side,
- slippage_percent: '0.5',
- reduce_only: false,
- client_order_id: clientOrderId
- };
- const result = await this.callApiWithRetry(
- () => client.createMarketOrder(order),
- `创建市场${side}订单 (${account.getId().slice(0,8)})`
- );
- if (result.success && result.data?.order_id) {
- const orderId = result.data.order_id.toString();
- const orderLifecycle: OrderLifecycle = {
- orderId,
- clientOrderId,
- accountId: account.getId(), // 记录账户ID
- symbol: 'BTC',
- side,
- amount: order.amount,
- price: '0', // market order has no fixed price
- status: 'pending',
- createdAt: Date.now(),
- lastChecked: Date.now(),
- checkCount: 0,
- maxChecks: 10
- };
- this.orderLifecycle.set(orderId, orderLifecycle);
- this.stats.totalOrders++;
- this.log(`创建市场订单: ${side.toUpperCase()} ${amount.toFixed(6)} BTC (${account.getId().slice(0,8)})`, 'info');
- }
- } catch (error) {
- this.log(`创建市场订单失败: ${side}`, 'error');
- }
- }
- /**
- * 重写初始化方法 - 完全自定义,不调用父类
- */
- public async initialize(): Promise<void> {
- try {
- this.log('开始初始化简洁版策略...', 'info');
- // 初始化账户配对 - Delta中性核心
- this.initializeAccountPairs();
- // 初始化并启动市场数据管理器
- if (this.marketDataManager) {
- await this.marketDataManager.initialize();
- this.log('市场数据管理器已启动 (WebSocket)', 'success');
- // 等待初始价格数据 (最多5秒)
- const priceTimeout = setTimeout(() => {
- if (!this.isPriceReady) {
- this.log('WebSocket价格未就绪,将使用REST API后备', 'warning');
- }
- }, 5000);
- // 等待价格就绪或超时
- for (let i = 0; i < 50 && !this.isPriceReady; i++) {
- await new Promise(resolve => setTimeout(resolve, 100));
- }
- clearTimeout(priceTimeout);
- }
- // 初始化并启动风险管理器
- if (this.riskManager) {
- await this.riskManager.initialize();
- await this.riskManager.startMonitoring(this.sessionId);
- this.log('风险管理器已启动', 'success');
- }
- // 启动配对刷量交易循环
- this.startPairedVolumeTrading();
- // 启动Delta再平衡监控
- this.startDeltaRebalancing();
- // 启动动态仓位管理器
- await this.startDynamicPositionManager();
- this.isInitialized = true;
- this.log('简洁版策略初始化成功', 'success');
- } catch (error) {
- this.log(`策略初始化失败`, 'error');
- throw error;
- }
- }
- /**
- * 启动配对刷量交易
- */
- private startPairedVolumeTrading(): void {
- // 启动刷量交易循环 - 每10秒执行一次
- this.volumeTradingInterval = setInterval(async () => {
- if (this.isTradingPaused) {
- return;
- }
- try {
- await this.executeVolumeTrades();
- } catch (error) {
- this.log('刷量交易周期失败', 'warning');
- }
- }, 10000);
- this.log('配对刷量交易已启动 (10秒间隔)', 'success');
- }
- /**
- * 启动Delta再平衡监控
- * 定期检查并修正仓位不平衡
- */
- private startDeltaRebalancing(): void {
- // 每60秒检查一次Delta平衡
- this.deltaMonitoringInterval = setInterval(async () => {
- if (this.isTradingPaused) {
- return;
- }
- try {
- await this.checkAndRebalanceDelta();
- } catch (error) {
- this.log('Delta再平衡检查失败', 'warning');
- }
- }, 60000);
- this.log('Delta再平衡监控已启动 (60秒间隔)', 'success');
- }
- /**
- * 检查并执行Delta再平衡
- */
- private async checkAndRebalanceDelta(): Promise<void> {
- try {
- // 获取所有账户的实时仓位
- const positions = await this.getAllAccountPositions();
- if (positions.length === 0) {
- return;
- }
- // 计算总净Delta
- let totalNetDelta = 0;
- let totalExposure = 0;
- for (const pos of positions) {
- totalNetDelta += pos.netPosition;
- totalExposure += Math.abs(pos.netPosition);
- }
- // 如果没有仓位,无需再平衡
- if (totalExposure === 0) {
- return;
- }
- // 计算Delta偏差百分比
- const deltaDeviationPercent = Math.abs(totalNetDelta / totalExposure);
- this.log(`Delta状态: 净Delta=${totalNetDelta.toFixed(8)} BTC, 偏差=${(deltaDeviationPercent * 100).toFixed(2)}%`, 'info');
- // 如果偏差超过阈值(例如5%),触发再平衡
- const REBALANCE_THRESHOLD = 0.05; // 5%阈值
- if (deltaDeviationPercent > REBALANCE_THRESHOLD) {
- this.log(`⚠️ Delta偏差过大 (${(deltaDeviationPercent * 100).toFixed(2)}%), 开始再平衡...`, 'warning');
- await this.executeDeltaRebalance(positions, totalNetDelta);
- }
- } catch (error) {
- this.log('Delta再平衡执行失败', 'error');
- }
- }
- /**
- * 获取所有账户的实时仓位
- */
- private async getAllAccountPositions(): Promise<Array<{account: Account, client: PacificaSigningClient, netPosition: number, amount: string, side: string}>> {
- const positions = [];
- for (const account of this.accounts) {
- const client = this.clientMap.get(account.getId());
- if (!client) {
- continue;
- }
- try {
- const result = await client.getAccountPositions();
- if (result.data && Array.isArray(result.data)) {
- const btcPos = result.data.find((p: any) => p.symbol === 'BTC');
- if (btcPos) {
- // bid = long (正), ask = short (负)
- const netPosition = btcPos.side === 'bid'
- ? parseFloat(btcPos.amount)
- : -parseFloat(btcPos.amount);
- positions.push({
- account,
- client,
- netPosition,
- amount: btcPos.amount,
- side: btcPos.side
- });
- }
- }
- } catch (error) {
- this.log(`获取账户${account.getId().slice(0,8)}仓位失败`, 'warning');
- }
- }
- return positions;
- }
- /**
- * 执行Delta再平衡
- * 通过调整账户仓位使净Delta接近零
- */
- private async executeDeltaRebalance(
- positions: Array<{account: Account, client: PacificaSigningClient, netPosition: number, amount: string, side: string}>,
- totalNetDelta: number
- ): Promise<void> {
- try {
- // 计算需要平衡的数量(净Delta的一半,分配到两个方向)
- const rebalanceAmount = Math.abs(totalNetDelta) / 2;
- // 确保满足最小订单要求
- const LOT_SIZE = 0.00001;
- const MIN_ORDER_VALUE = 10;
- const currentPrice = this.currentBTCPrice || 113000;
- const minBtcAmount = MIN_ORDER_VALUE / currentPrice;
- const MIN_ORDER_SIZE = Math.ceil(minBtcAmount / LOT_SIZE) * LOT_SIZE;
- let adjustedRebalanceAmount = Math.floor(rebalanceAmount / LOT_SIZE) * LOT_SIZE;
- if (adjustedRebalanceAmount < MIN_ORDER_SIZE) {
- this.log(`再平衡数量过小 (${adjustedRebalanceAmount.toFixed(8)} < ${MIN_ORDER_SIZE.toFixed(8)}), 跳过`, 'info');
- return;
- }
- // 找出净多头和净空头账户
- const longPositions = positions.filter(p => p.netPosition > 0);
- const shortPositions = positions.filter(p => p.netPosition < 0);
- if (totalNetDelta > 0) {
- // 净多头过多:减少多头仓位,增加空头仓位
- this.log(`执行再平衡: 减少${adjustedRebalanceAmount.toFixed(8)} BTC多头`, 'info');
- // 在最大多头账户上减仓
- if (longPositions.length > 0) {
- const maxLongAccount = longPositions.reduce((max, p) =>
- p.netPosition > max.netPosition ? p : max
- );
- await this.executeRebalanceOrder(
- maxLongAccount.account,
- maxLongAccount.client,
- adjustedRebalanceAmount,
- 'ask' // 平多头 = 卖出
- );
- }
- // 在最小空头账户上加仓
- if (shortPositions.length > 0) {
- const minShortAccount = shortPositions.reduce((min, p) =>
- Math.abs(p.netPosition) < Math.abs(min.netPosition) ? p : min
- );
- await this.executeRebalanceOrder(
- minShortAccount.account,
- minShortAccount.client,
- adjustedRebalanceAmount,
- 'ask' // 增加空头 = 卖出
- );
- } else {
- // 如果没有空头账户,在另一个多头账户上开空
- if (longPositions.length > 1) {
- const minLongAccount = longPositions.reduce((min, p) =>
- p.netPosition < min.netPosition ? p : min
- );
- await this.executeRebalanceOrder(
- minLongAccount.account,
- minLongAccount.client,
- adjustedRebalanceAmount,
- 'ask'
- );
- }
- }
- } else {
- // 净空头过多:减少空头仓位,增加多头仓位
- this.log(`执行再平衡: 减少${adjustedRebalanceAmount.toFixed(8)} BTC空头`, 'info');
- // 在最大空头账户上减仓
- if (shortPositions.length > 0) {
- const maxShortAccount = shortPositions.reduce((max, p) =>
- Math.abs(p.netPosition) > Math.abs(max.netPosition) ? p : max
- );
- await this.executeRebalanceOrder(
- maxShortAccount.account,
- maxShortAccount.client,
- adjustedRebalanceAmount,
- 'bid' // 平空头 = 买入
- );
- }
- // 在最小多头账户上加仓
- if (longPositions.length > 0) {
- const minLongAccount = longPositions.reduce((min, p) =>
- p.netPosition < min.netPosition ? p : min
- );
- await this.executeRebalanceOrder(
- minLongAccount.account,
- minLongAccount.client,
- adjustedRebalanceAmount,
- 'bid' // 增加多头 = 买入
- );
- } else {
- // 如果没有多头账户,在另一个空头账户上开多
- if (shortPositions.length > 1) {
- const minShortAccount = shortPositions.reduce((min, p) =>
- Math.abs(p.netPosition) < Math.abs(min.netPosition) ? p : min
- );
- await this.executeRebalanceOrder(
- minShortAccount.account,
- minShortAccount.client,
- adjustedRebalanceAmount,
- 'bid'
- );
- }
- }
- }
- this.log('✅ Delta再平衡完成', 'success');
- } catch (error) {
- this.log('Delta再平衡执行失败', 'error');
- }
- }
- /**
- * 执行再平衡订单
- */
- private async executeRebalanceOrder(
- account: Account,
- client: PacificaSigningClient,
- amount: number,
- side: 'bid' | 'ask'
- ): Promise<void> {
- try {
- const clientOrderId = uuidv4();
- const order = {
- symbol: 'BTC',
- amount: amount.toFixed(8),
- side,
- slippage_percent: '0.5',
- reduce_only: false,
- client_order_id: clientOrderId
- };
- const result = await this.callApiWithRetry(
- () => client.createMarketOrder(order),
- `再平衡订单 (${account.getId().slice(0,8)} ${side})`
- );
- if (result.success) {
- this.log(`✅ 再平衡订单: ${account.getId().slice(0,8)} ${side.toUpperCase()} ${amount.toFixed(8)} BTC`, 'success');
- }
- } catch (error) {
- this.log(`再平衡订单失败: ${account.getId().slice(0,8)} ${side}`, 'error');
- }
- }
- /**
- * 初始化账户配对机制
- * 确保Delta中性: 每个买单都有对应的卖单
- */
- private initializeAccountPairs(): void {
- if (this.accounts.length < 2) {
- throw new Error('需要至少2个账户进行Delta中性对冲');
- }
- if (this.accounts.length % 2 !== 0) {
- this.log(`警告: 账户数量为奇数(${this.accounts.length}), 最后一个账户将不参与配对`, 'warning');
- }
- this.accountPairs = [];
- for (let i = 0; i < this.accounts.length - 1; i += 2) {
- this.accountPairs.push([this.accounts[i], this.accounts[i + 1]]);
- }
- this.log(`账户配对完成: ${this.accountPairs.length}对账户`, 'success');
- this.accountPairs.forEach((pair, index) => {
- this.log(` 配对${index + 1}: ${pair[0].getId()} (买) <-> ${pair[1].getId()} (卖)`, 'info');
- });
- }
- /**
- * 检查账户余额
- * @param account 账户
- * @param client 客户端
- * @param requiredAmount 需要的金额(USDC或BTC)
- * @param isBTC 是否检查BTC余额
- */
- private async checkAccountBalance(
- account: Account,
- client: PacificaSigningClient,
- requiredAmount: number,
- isBTC: boolean = false
- ): Promise<boolean> {
- try {
- const accountInfo = await client.getAccountInfo();
- if (isBTC) {
- // 检查BTC持仓
- const positions = await client.getAccountPositions();
- const btcPositions = Array.isArray(positions.data) ?
- positions.data.filter((p: any) => p.symbol === 'BTC') : [];
- const totalBTC = btcPositions.reduce((sum: number, p: any) => {
- return sum + Math.abs(parseFloat(p.amount));
- }, 0);
- return totalBTC >= requiredAmount;
- } else {
- // 检查USDC余额
- const availableBalance = parseFloat(accountInfo.data.available_to_spend);
- const marginBuffer = 1.1; // 10%缓冲
- return availableBalance >= requiredAmount * marginBuffer;
- }
- } catch (error) {
- this.log(`检查余额失败: ${account.getId().slice(0,8)}`, 'error');
- return false;
- }
- }
- /**
- * 处理余额不足
- */
- private handleInsufficientBalance(): void {
- if (!this.insufficientBalanceCount) {
- this.insufficientBalanceCount = 0;
- }
- this.insufficientBalanceCount++;
- // 如果连续5次余额不足,暂停交易
- if (this.insufficientBalanceCount >= 5) {
- this.log('⚠️ 连续余额不足,暂停交易60秒', 'warning');
- this.isTradingPaused = true;
- // 60秒后恢复
- setTimeout(() => {
- this.isTradingPaused = false;
- this.insufficientBalanceCount = 0;
- this.log('✅ 恢复交易', 'success');
- }, 60000);
- }
- }
- private insufficientBalanceCount: number = 0;
- /**
- * 重写停止方法
- */
- public async stop(): Promise<void> {
- this.log('停止简洁版策略...', 'info');
- // 清理定时器
- if (this.volumeTradingInterval) {
- clearInterval(this.volumeTradingInterval);
- this.volumeTradingInterval = null;
- }
- if (this.deltaMonitoringInterval) {
- clearInterval(this.deltaMonitoringInterval);
- this.deltaMonitoringInterval = null;
- }
- if (this.orderCheckInterval) {
- clearInterval(this.orderCheckInterval);
- this.orderCheckInterval = null;
- }
- if (this.statusDisplayInterval) {
- clearInterval(this.statusDisplayInterval);
- this.statusDisplayInterval = null;
- }
- if (this.statsSaveInterval) {
- clearInterval(this.statsSaveInterval);
- this.statsSaveInterval = null;
- }
- if (this.healthCheckInterval) {
- clearInterval(this.healthCheckInterval);
- this.healthCheckInterval = null;
- }
- // 停止动态仓位管理器
- if (this.dynamicPositionManager) {
- this.dynamicPositionManager.shutdown();
- this.log('动态仓位管理器已停止', 'success');
- }
- // 使用 OrderCleanupService 取消所有开放订单
- console.log('\n🧹 正在从 Pacifica API 获取开放订单...');
- this.log('清理所有开放订单...', 'info');
- try {
- const cleanupService = new OrderCleanupService();
- // 为每个账户初始化清理服务
- for (const account of this.accounts) {
- cleanupService.initializeAccount(account);
- }
- // 强制清理所有订单
- const cleanupOptions: CleanupOptions = {
- cleanAll: true,
- includeReduceOnly: true, // 包括保护性订单
- mode: 'force', // 强制模式
- dryRun: false
- };
- console.log('从 API 获取订单并取消...');
- const results = await cleanupService.cleanupMultipleAccounts(
- this.accounts,
- cleanupOptions
- );
- // 汇总清理结果
- let totalOrders = 0;
- let totalCancelled = 0;
- for (const result of results.values()) {
- totalOrders += result.totalOrders;
- totalCancelled += result.cancelledOrders;
- }
- console.log(`📊 从 API 获取到 ${totalOrders} 个开放订单`);
- if (totalCancelled > 0) {
- console.log(`✅ 已取消 ${totalCancelled} 个开放订单`);
- this.log(`已取消 ${totalCancelled} 个开放订单`, 'success');
- } else {
- console.log('✅ 没有需要清理的订单');
- this.log('没有需要清理的订单', 'info');
- }
- await cleanupService.shutdown();
- } catch (error) {
- this.log('⚠️ 订单清理失败,尝试手动取消', 'warning');
- // 降级处理:手动取消内存中的订单
- for (const [orderId, order] of this.orderLifecycle) {
- if (order.status === 'pending') {
- try {
- await this.cancelOrderSafely(orderId, order.symbol);
- } catch (error) {
- this.log(`取消订单失败: ${orderId}`, 'error');
- }
- }
- }
- }
- // 清理生命周期记录
- this.orderLifecycle.clear();
- // 停止市场数据管理器
- if (this.marketDataManager) {
- await this.marketDataManager.disconnect();
- this.log('市场数据管理器已停止', 'info');
- }
- // 停止风险管理器
- if (this.riskManager) {
- await this.riskManager.stopMonitoring(this.sessionId);
- await this.riskManager.shutdown();
- this.log('风险管理器已停止', 'info');
- }
- // 保存最终统计
- this.saveStats();
- // 显示最终统计
- this.displayFinalStats();
- // 调用父类停止方法
- await super.stop();
- this.log('简洁版策略已停止', 'success');
- }
- /**
- * 显示最终统计
- */
- private displayFinalStats(): void {
- const runtime = Math.floor((Date.now() - this.stats.startTime) / 1000);
- const runtimeStr = `${Math.floor(runtime / 3600)}时${Math.floor((runtime % 3600) / 60)}分${runtime % 60}秒`;
- console.log('\n' + '='.repeat(50));
- console.log('📊 简洁版策略最终统计');
- console.log('='.repeat(50));
- console.log(`⏰ 总运行时间: ${runtimeStr}`);
- console.log(`📊 总订单数: ${this.stats.totalOrders}`);
- console.log(`✅ 已成交: ${this.stats.filledOrders}`);
- console.log(`❌ 已取消: ${this.stats.cancelledOrders}`);
- console.log(`📈 总交易量: ${this.stats.totalVolume.toFixed(6)} BTC`);
- console.log(`💰 总PNL: ${this.stats.totalPnL.toFixed(2)} USDC`);
- console.log(`🌐 API调用: ${this.stats.apiCallCount}`);
- console.log(`🔄 总重试次数: ${this.stats.totalRetries}`);
- console.log(`⚠️ 最大连续错误: ${this.stats.consecutiveErrors}`);
- if (this.stats.totalOrders > 0) {
- const successRate = ((this.stats.filledOrders / this.stats.totalOrders) * 100).toFixed(1);
- const avgVolume = (this.stats.totalVolume / this.stats.filledOrders).toFixed(6);
- console.log(`🎯 成交率: ${successRate}%`);
- console.log(`📊 平均交易量: ${avgVolume} BTC`);
- }
- console.log('='.repeat(50) + '\n');
- }
- }
- async function runSimpleDeltaNeutralStrategy() {
- console.log('🚀 启动简洁版Delta中性刷量策略...\n');
- try {
- // 1. 加载配置
- console.log('📋 加载配置文件...');
- const accountsConfig = JSON.parse(readFileSync('./config/accounts.json', 'utf-8'));
- const strategyConfig = JSON.parse(readFileSync('./config/trading-strategy.json', 'utf-8'));
- console.log(`✅ 账户配置: ${accountsConfig.length} 个账户`);
- console.log(`✅ 策略配置: ${strategyConfig.orderStrategy.preferredOrderType}单优先`);
- // 2. 初始化Pacifica客户端
- console.log('\n🔗 初始化Pacifica客户端...');
- const privateKey = accountsConfig[0].privateKey;
- const pacificaClient = new PacificaSigningClient(privateKey);
- console.log('✅ Pacifica客户端初始化成功');
- console.log(`公钥: ${pacificaClient.getPublicKey()}`);
- // 3. 获取当前市场信息(带重试)
- console.log('\n📊 获取当前市场信息...');
- let prices, marketInfo, accountInfo;
- let retryCount = 0;
- const maxRetries = 3;
- while (retryCount < maxRetries) {
- try {
- prices = await pacificaClient.getPrices();
- marketInfo = await pacificaClient.getMarketInfo();
- accountInfo = await pacificaClient.getAccountInfo();
- break;
- } catch (error) {
- retryCount++;
- console.log(`⚠️ 获取市场信息失败 (尝试 ${retryCount}/${maxRetries})`);
- if (retryCount < maxRetries) {
- const delay = 10000 * retryCount;
- console.log(`等待 ${delay/1000} 秒后重试...`);
- await new Promise(resolve => setTimeout(resolve, delay));
- } else {
- throw error;
- }
- }
- }
- const btcPrice = prices.data.find((p: any) => p.symbol === 'BTC');
- const btcMarket = marketInfo.data.find((m: any) => m.symbol === 'BTC');
- const currentPrice = parseFloat(btcPrice.mark);
- const accountBalance = parseFloat(accountInfo.data.balance);
- const minOrderSize = parseFloat(btcMarket.min_order_size);
- const lotSize = parseFloat(btcMarket.lot_size);
- console.log('✅ 市场信息获取成功');
- console.log(`BTC当前价格: ${currentPrice}`);
- console.log(`账户余额: ${accountBalance} USDC`);
- console.log(`最小订单大小: ${minOrderSize} USDC`);
- // 4. 计算仓位大小(基于配置)
- console.log('\n💰 计算仓位大小...');
- const minOrderValue = Math.max(minOrderSize, strategyConfig.positions.minOrderValue);
- const availableBalance = accountBalance * strategyConfig.positions.balanceUsageRatio;
- // 基础仓位
- const basePositionValue = Math.max(
- availableBalance * strategyConfig.positions.basePositionRatio,
- minOrderValue * 1.05
- );
- const basePositionSize = basePositionValue / currentPrice;
- const adjustedBaseSize = Math.ceil(basePositionSize / lotSize) * lotSize;
- // 刷量仓位
- const volumePositionValue = Math.max(
- availableBalance * strategyConfig.positions.volumePositionRatio,
- minOrderValue
- );
- const volumePositionSize = volumePositionValue / currentPrice;
- const adjustedVolumeSize = Math.ceil(volumePositionSize / lotSize) * lotSize;
- console.log(`可用余额: ${availableBalance.toFixed(2)} USDC (${(strategyConfig.positions.balanceUsageRatio * 100).toFixed(0)}%)`);
- console.log(`基础仓位: ${adjustedBaseSize.toFixed(8)} BTC (${(adjustedBaseSize * currentPrice).toFixed(2)} USDC)`);
- console.log(`刷量仓位: ${adjustedVolumeSize.toFixed(8)} BTC (${(adjustedVolumeSize * currentPrice).toFixed(2)} USDC)`);
- // 5. 构建策略配置(从配置文件)
- console.log('\n⚙️ 构建策略配置...');
- const configManager = new DeltaNeutralConfigManager();
- const simpleConfig: DeltaNeutralConfig = {
- // 基础仓位配置
- basePositionRatio: strategyConfig.positions.basePositionRatio,
- basePositionSize: adjustedBaseSize,
- // 刷量仓位配置
- volumePositionRatio: strategyConfig.positions.volumePositionRatio,
- maxVolumePositionSize: adjustedVolumeSize,
- // Delta中性配置
- maxDeltaDeviation: strategyConfig.deltaRebalancing.maxDeltaDeviation,
- rebalanceThreshold: strategyConfig.deltaRebalancing.rebalanceThreshold,
- // 交易配置 - 限价单优先(降低手续费)
- preferredOrderType: strategyConfig.orderStrategy.preferredOrderType as 'limit' | 'market',
- limitOrderSpread: strategyConfig.orderStrategy.limitOrderSpread,
- emergencyMarketThreshold: strategyConfig.orderStrategy.emergencyMarketThreshold,
- // 风险控制
- maxDrawdown: strategyConfig.risk.maxDrawdown,
- maxPositionSize: adjustedBaseSize * strategyConfig.risk.positionSizeMultiplier,
- stopLossThreshold: strategyConfig.risk.stopLossThreshold
- };
- configManager.updateConfig(simpleConfig);
- console.log('✅ 策略配置完成');
- console.log(`订单类型: ${simpleConfig.preferredOrderType}单优先`);
- console.log(`价差: ${(simpleConfig.limitOrderSpread * 100).toFixed(3)}%`);
- console.log(`Delta偏差限制: ${(simpleConfig.maxDeltaDeviation * 100).toFixed(1)}%`);
- console.log(`最大回撤: ${(simpleConfig.maxDrawdown * 100).toFixed(1)}%`);
- // 6. 创建账户对象
- const accounts: Account[] = accountsConfig.map((acc: any) => new Account({
- id: acc.id,
- name: acc.name,
- privateKey: acc.privateKey,
- apiKey: acc.apiKey || 'not_required',
- address: acc.address,
- isActive: acc.isActive !== false,
- balance: {
- total: accountBalance,
- available: availableBalance,
- used: 0
- },
- positions: []
- }));
- // 7. 创建简洁版策略实例
- console.log('\n🎯 创建简洁版策略实例...');
- const strategy = new SimpleDeltaNeutralStrategy(
- simpleConfig,
- pacificaClient,
- accounts
- );
- console.log('✅ 简洁版策略创建成功');
- // 8. 清理历史订单(策略启动前)
- console.log('\n🧹 清理历史开放订单...');
- try {
- const cleanupService = new OrderCleanupService();
- // 为每个账户初始化清理服务
- for (const account of accounts) {
- cleanupService.initializeAccount(account);
- }
- // 清理选项:清理所有非 reduce_only 订单
- const cleanupOptions: CleanupOptions = {
- cleanAll: true,
- includeReduceOnly: false, // 保留保护性订单
- mode: 'selective',
- dryRun: false
- };
- console.log('正在从 Pacifica API 获取开放订单...');
- const results = await cleanupService.cleanupMultipleAccounts(
- accounts,
- cleanupOptions
- );
- // 汇总清理结果
- let totalOrders = 0;
- let totalCancelled = 0;
- let totalFailed = 0;
- for (const [accountId, result] of results.entries()) {
- totalOrders += result.totalOrders;
- totalCancelled += result.cancelledOrders;
- totalFailed += result.failedOrders;
- if (result.totalOrders > 0) {
- console.log(` 账户 ${accountId.slice(0, 8)}: ${result.totalOrders} 个订单, 已取消 ${result.cancelledOrders}, 失败 ${result.failedOrders}`);
- }
- }
- if (totalOrders > 0) {
- console.log(`✅ 历史订单清理完成: ${totalCancelled}/${totalOrders} 个订单已取消`);
- if (totalFailed > 0) {
- console.log(`⚠️ ${totalFailed} 个订单取消失败`);
- }
- } else {
- console.log('✅ 没有历史开放订单需要清理');
- }
- await cleanupService.shutdown();
- } catch (error) {
- console.log('⚠️ 历史订单清理失败,继续启动策略');
- console.log(`错误: ${error instanceof Error ? error.message : '未知错误'}`);
- }
- // 9. 显示策略信息
- console.log('\n📋 简洁版策略特点:');
- console.log('• 超保守参数 - 2%基础仓位 + 5%刷量仓位');
- console.log('• 严格风险控制 - 1%最大回撤,0.1%Delta偏差');
- console.log('• 智能重试机制 - 自动重试失败的API调用');
- console.log('• 智能错误恢复 - 连续错误自动暂停和恢复');
- console.log('• 健康检查系统 - 5分钟间隔健康监控');
- console.log('• 统计信息持久化 - 10分钟间隔保存统计');
- console.log('• 完整的生命周期管理 - 订单自动跟踪和清理');
- console.log('• 自动订单清理 - 启动前/停止后自动清理');
- console.log('• API频率控制 - 2秒间隔,避免限制');
- console.log('• 简洁日志输出 - 只显示关键信息');
- console.log('\n🔄 开始执行简洁版策略...');
- // 9. 初始化策略
- await strategy.initialize();
- console.log('✅ 策略初始化完成');
- // 10. 启动策略
- console.log('\n📊 简洁版策略已启动,开始简洁运行...');
- console.log('按 Ctrl+C 停止策略');
- // 11. 优雅关闭处理
- process.on('SIGINT', async () => {
- console.log('\n🛑 收到停止信号,正在优雅关闭策略...');
- try {
- await strategy.stop();
- console.log('✅ 策略已安全停止');
- process.exit(0);
- } catch (error) {
- console.error('❌ 停止策略时发生错误:', error);
- process.exit(1);
- }
- });
- // 12. 错误处理
- process.on('uncaughtException', async (error) => {
- console.error('❌ 未捕获的异常:', error);
- try {
- await strategy.stop();
- } catch (stopError) {
- console.error('❌ 停止策略时发生错误:', stopError);
- }
- process.exit(1);
- });
- process.on('unhandledRejection', async (reason) => {
- console.error('❌ 未处理的Promise拒绝:', reason);
- try {
- await strategy.stop();
- } catch (stopError) {
- console.error('❌ 停止策略时发生错误:', stopError);
- }
- process.exit(1);
- });
- console.log('\n🎉 简洁版Delta中性刷量策略已启动!');
- console.log('策略将持续简洁运行,自动处理API错误和网络问题...');
- } catch (error) {
- console.error('❌ 策略启动失败:', error);
- process.exit(1);
- }
- }
- // 运行策略
- runSimpleDeltaNeutralStrategy().catch(console.error);
|