123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043 |
- #!/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 accountPnL: Map<string, {
- totalProfit: number; // 累计利润(USDC)
- totalVolume: number; // 累计成交量(BTC)
- winTrades: number; // 盈利交易次数
- lossTrades: number; // 亏损交易次数
- lastUpdateTime: number; // 最后更新时间
- initialBalance: number; // 初始余额
- currentBalance: number; // 当前余额
- direction: 'long' | 'short' | 'neutral'; // 主要方向
- performance: number; // 绩效得分(用于动态角色分配)
- }> = new Map();
- // 市场趋势跟踪
- private marketTrend: 'bullish' | 'bearish' | 'neutral' = 'neutral';
- private priceHistory: number[] = []; // 保存最近100个价格
- private buyRatio: number = 0.5; // 买单比例
- private sellRatio: number = 0.5; // 卖单比例
- private lastBTCPrice: number = 0; // 最新BTC价格
- // 配置参数
- 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轮询
- * 传入signing client以支持认证订阅(如account balance)
- */
- private initializeMarketDataManager(): void {
- this.marketDataManager = new MarketDataManager(this.pacificaClient);
- // 监听实时价格更新
- this.marketDataManager.on('price_update', (priceData) => {
- if (priceData.symbol === 'BTC') {
- this.currentBTCPrice = parseFloat(priceData.mark);
- this.lastBTCPrice = this.currentBTCPrice; // 同步更新最新价格
- 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}%`);
- }
- // 显示账户盈亏报告
- this.displayAccountPnL();
- // 显示健康状态
- const healthStatus = this.stats.consecutiveErrors === 0 ? '🟢 健康' : '🔴 异常';
- console.log(`🏥 健康状态: ${healthStatus}`);
- console.log('='.repeat(50) + '\n');
- }
- /**
- * 显示账户盈亏报告
- */
- private displayAccountPnL(): void {
- if (this.accountPnL.size === 0) {
- return;
- }
- console.log('\n💼 账户盈亏报告');
- console.log('-'.repeat(50));
- let totalProfit = 0;
- let totalVolume = 0;
- let profitableAccounts = 0;
- // 收集账户数据
- const accountData: Array<{
- id: string;
- profit: number;
- volume: number;
- winRate: number;
- direction: string;
- }> = [];
- this.accountPnL.forEach((pnl, accountId) => {
- const winRate = pnl.performance;
- totalProfit += pnl.totalProfit;
- totalVolume += pnl.totalVolume;
- if (pnl.totalProfit > 0) {
- profitableAccounts++;
- }
- accountData.push({
- id: accountId.slice(0, 8),
- profit: pnl.totalProfit,
- volume: pnl.totalVolume,
- winRate: winRate,
- direction: pnl.direction
- });
- });
- // 按利润排序
- accountData.sort((a, b) => b.profit - a.profit);
- // 显示前5个账户
- accountData.slice(0, 5).forEach(acc => {
- const profitIcon = acc.profit > 0 ? '✅' : '❌';
- const directionIcon = acc.direction === 'long' ? '🔺' : acc.direction === 'short' ? '🔻' : '⚖️';
- console.log(
- `${profitIcon} ${acc.id} ${directionIcon}: ` +
- `盈亏 ${acc.profit.toFixed(2)} USDC | ` +
- `成交量 ${acc.volume.toFixed(6)} BTC | ` +
- `胜率 ${acc.winRate.toFixed(1)}%`
- );
- });
- console.log('-'.repeat(50));
- console.log(`📊 总体盈亏: ${totalProfit.toFixed(2)} USDC`);
- console.log(`✅ 盈利账户: ${profitableAccounts}/${this.accountPnL.size} (${(profitableAccounts/this.accountPnL.size*100).toFixed(1)}%)`);
- console.log(`📈 总成交量: ${totalVolume.toFixed(6)} BTC`);
- // 检查是否达到目标
- if (profitableAccounts > 0) {
- console.log(`🎯 已达成目标: 至少有${profitableAccounts}个方向的账户盈利!`);
- }
- }
- /**
- * 检查订单生命周期
- */
- 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();
- // 更新账户PnL跟踪
- if (order.accountId) {
- this.updateAccountPnL(
- order.accountId,
- order.side,
- parseFloat(order.amount),
- parseFloat(order.price),
- true
- );
- }
- 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');
- }
- }
- /**
- * 更新账户PnL跟踪
- */
- private updateAccountPnL(
- accountId: string,
- side: 'bid' | 'ask',
- amount: number,
- price: number,
- success: boolean
- ): void {
- // 获取或创建账户PnL记录
- let pnl = this.accountPnL.get(accountId);
- if (!pnl) {
- pnl = {
- totalProfit: 0,
- totalVolume: 0,
- winTrades: 0,
- lossTrades: 0,
- lastUpdateTime: Date.now(),
- initialBalance: 0,
- currentBalance: 0,
- direction: 'neutral' as 'long' | 'short' | 'neutral',
- performance: 0
- };
- this.accountPnL.set(accountId, pnl);
- }
- // 更新交易量
- pnl.totalVolume += amount;
- pnl.lastUpdateTime = Date.now();
- if (success) {
- // 使用当前价格计算盈亏
- const currentMarketPrice = this.lastBTCPrice || price;
- const spread = Math.abs(currentMarketPrice - price) / currentMarketPrice;
- // 买低卖高策略的盈亏计算
- if (side === 'bid') {
- // 买单:买入价格低于市场价,记为盈利
- const profit = spread * amount * price;
- pnl.totalProfit += profit;
- pnl.winTrades++;
- pnl.direction = 'long'; // 买入倾向
- this.log(`💰 买单盈利: ${profit.toFixed(2)} USDC (价差 ${(spread * 100).toFixed(2)}%)`, 'info');
- } else {
- // 卖单:卖出价格高于市场价,记为盈利
- const profit = spread * amount * price;
- pnl.totalProfit += profit;
- pnl.winTrades++;
- pnl.direction = 'short'; // 卖出倾向
- this.log(`💰 卖单盈利: ${profit.toFixed(2)} USDC (价差 ${(spread * 100).toFixed(2)}%)`, 'info');
- }
- } else {
- pnl.lossTrades++;
- }
- // 计算绩效分数
- const totalTrades = pnl.winTrades + pnl.lossTrades;
- if (totalTrades > 0) {
- pnl.performance = (pnl.winTrades / totalTrades) * 100;
- }
- }
- /**
- * 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 {
- // 使用不对称价差实现买低卖高套利
- let spread: number;
- // 从配置文件读取价差设置(实际部署时从配置加载)
- const asymmetricSpread = true; // 启用不对称价差
- const bidSpread = 0.015; // 买单价差1.5%
- const askSpread = 0.015; // 卖单价差1.5%
- if (asymmetricSpread) {
- // 买低卖高策略:买单使用更大的负价差,卖单使用更大的正价差
- spread = side === 'bid' ? bidSpread : askSpread;
- // 记录价差利润预期
- const expectedProfit = spread * 100;
- this.log(`💰 套利价差: ${side === 'bid' ? '买' : '卖'}单 -${expectedProfit.toFixed(1)}% (${side === 'bid' ? '买低' : '卖高'})`, 'info');
- } else {
- // 传统对称价差
- spread = this.config.limitOrderSpread || 0.005;
- }
- 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 bidSlippage = '0.3'; // 买单使用较小滑点(0.3%)
- const askSlippage = '0.7'; // 卖单使用较大滑点(0.7%)
- const slippage = side === 'bid' ? bidSlippage : askSlippage;
- this.log(`💹 市价单滑点策略: ${side === 'bid' ? '买' : '卖'}单 ${slippage}% 滑点`, 'info');
- const clientOrderId = uuidv4();
- const order = {
- symbol: 'BTC',
- amount: amount.toFixed(8),
- side,
- slippage_percent: slippage,
- 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');
- }
- }
- /**
- * 重写初始化方法 - 完全基于WebSocket获取数据
- */
- public async initialize(): Promise<void> {
- try {
- this.log('开始初始化简洁版策略...', 'info');
- // 1. 初始化账户配对 - Delta中性核心
- this.initializeAccountPairs();
- // 2. 初始化并启动市场数据管理器
- if (this.marketDataManager) {
- await this.marketDataManager.initialize();
- this.log('市场数据管理器已启动 (WebSocket自动订阅)', 'success');
- // 等待价格数据就绪 (最多10秒)
- console.log('⏳ 等待WebSocket价格数据就绪...');
- for (let i = 0; i < 100; i++) {
- if (this.isPriceReady) {
- break;
- }
- await new Promise(resolve => setTimeout(resolve, 100));
- }
- // 检查价格数据是否就绪
- if (!this.isPriceReady) {
- throw new Error('WebSocket价格数据未就绪,初始化失败');
- }
- console.log(`✅ WebSocket价格数据就绪: $${this.currentBTCPrice.toFixed(2)}`);
- // 获取账户余额 (使用REST API,仅初始化时调用一次)
- // WebSocket balance订阅需要特殊认证,暂时使用REST API
- console.log('📊 通过REST API获取账户余额...');
- const accountInfo = await this.pacificaClient.getAccountInfo();
- const balanceData = {
- total: parseFloat(accountInfo.balance),
- available: parseFloat(accountInfo.available_to_spend),
- locked: parseFloat(accountInfo.balance) - parseFloat(accountInfo.available_to_spend),
- timestamp: Date.now()
- };
- console.log(`✅ 账户余额: ${balanceData.available.toFixed(2)} USDC (可用), ${balanceData.total.toFixed(2)} USDC (总计)`);
- // 3. 从配置文件读取策略配置
- const strategyConfig = JSON.parse(readFileSync('./config/trading-strategy.json', 'utf-8'));
- // 4. 计算仓位大小(基于WebSocket实时数据)
- const LOT_SIZE = 0.00001; // BTC最小订单大小
- const MIN_ORDER_VALUE = 10; // $10最低订单价值
- // 计算满足$10最低要求的BTC数量
- const minBtcAmount = MIN_ORDER_VALUE / this.currentBTCPrice;
- const minOrderSize = Math.ceil(minBtcAmount / LOT_SIZE) * LOT_SIZE;
- const availableBalance = balanceData.available * strategyConfig.positions.balanceUsageRatio;
- // 基础仓位
- const basePositionValue = Math.max(
- availableBalance * strategyConfig.positions.basePositionRatio,
- MIN_ORDER_VALUE * 1.05
- );
- const basePositionSize = basePositionValue / this.currentBTCPrice;
- const adjustedBaseSize = Math.ceil(basePositionSize / LOT_SIZE) * LOT_SIZE;
- // 刷量仓位
- const volumePositionValue = Math.max(
- availableBalance * strategyConfig.positions.volumePositionRatio,
- MIN_ORDER_VALUE
- );
- const volumePositionSize = volumePositionValue / this.currentBTCPrice;
- const adjustedVolumeSize = Math.ceil(volumePositionSize / LOT_SIZE) * LOT_SIZE;
- console.log(`💰 计算仓位: 可用=${availableBalance.toFixed(2)} USDC, 基础=${adjustedBaseSize.toFixed(8)} BTC, 刷量=${adjustedVolumeSize.toFixed(8)} BTC`);
- // 5. 构建并更新策略配置
- const configManager = new DeltaNeutralConfigManager();
- const updatedConfig: DeltaNeutralConfig = {
- basePositionRatio: strategyConfig.positions.basePositionRatio,
- basePositionSize: adjustedBaseSize,
- volumePositionRatio: strategyConfig.positions.volumePositionRatio,
- maxVolumePositionSize: adjustedVolumeSize,
- 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(updatedConfig);
- this.updateStrategyConfig(updatedConfig); // 更新策略实例的配置
- console.log(`✅ 策略配置完成: ${updatedConfig.preferredOrderType}单优先, 价差=${(updatedConfig.limitOrderSpread * 100).toFixed(3)}%`);
- }
- // 初始化并启动风险管理器
- 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); // 使用10秒间隔,减少API调用
- 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}单优先\n`);
- // 2. 创建账户对象(余额由WebSocket更新)
- 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: 0, // 将由WebSocket更新
- available: 0, // 将由WebSocket更新
- used: 0
- },
- positions: []
- }));
- // 3. 创建简洁版策略实例
- console.log('🎯 创建简洁版策略实例...');
- const privateKey = accountsConfig[0].privateKey;
- const pacificaClient = new PacificaSigningClient(privateKey);
- // 创建初始配置(仓位大小将在initialize()中由WebSocket数据计算)
- const initialConfig: DeltaNeutralConfig = {
- basePositionRatio: strategyConfig.positions.basePositionRatio,
- basePositionSize: 0, // 将由initialize()计算
- volumePositionRatio: strategyConfig.positions.volumePositionRatio,
- maxVolumePositionSize: 0, // 将由initialize()计算
- 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: 0, // 将由initialize()计算
- stopLossThreshold: strategyConfig.risk.stopLossThreshold
- };
- const strategy = new SimpleDeltaNeutralStrategy(
- initialConfig,
- pacificaClient,
- accounts
- );
- console.log('✅ 简洁版策略创建成功\n');
- // 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. 初始化策略
- 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);
|