run-delta-neutral-simple.ts 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888
  1. #!/usr/bin/env tsx
  2. /**
  3. * 简洁版Delta中性刷量策略
  4. * 只显示关键信息,日志简洁清晰
  5. */
  6. import { DeltaNeutralVolumeStrategy, DeltaNeutralConfig } from '../src/strategies/DeltaNeutralVolumeStrategy';
  7. import { DeltaNeutralConfigManager } from '../src/strategies/DeltaNeutralConfig';
  8. import { PacificaSigningClient } from '../src/services/PacificaSigningClient';
  9. import { RiskManager, RiskManagerConfig } from '../src/core/RiskManager';
  10. import { MarketDataManager } from '../src/services/MarketDataManager';
  11. import { OrderCleanupService, CleanupOptions } from '../src/services/OrderCleanupService';
  12. import { DynamicPositionManager, PositionAdjustmentConfig } from '../src/services/DynamicPositionManager';
  13. import { Account } from '../src/models/Account';
  14. import { readFileSync, writeFileSync, existsSync } from 'fs';
  15. import { v4 as uuidv4 } from 'uuid';
  16. interface OrderLifecycle {
  17. orderId: string;
  18. clientOrderId: string;
  19. accountId: string; // 记录创建订单的账户ID
  20. symbol: string;
  21. side: 'bid' | 'ask';
  22. amount: string;
  23. price: string;
  24. status: 'pending' | 'filled' | 'cancelled' | 'expired';
  25. createdAt: number;
  26. lastChecked: number;
  27. checkCount: number;
  28. maxChecks: number;
  29. }
  30. interface SimpleStats {
  31. totalOrders: number;
  32. filledOrders: number;
  33. cancelledOrders: number;
  34. expiredOrders: number;
  35. totalVolume: number;
  36. totalPnL: number;
  37. startTime: number;
  38. lastUpdateTime: number;
  39. consecutiveErrors: number;
  40. maxConsecutiveErrors: number;
  41. apiCallCount: number;
  42. lastApiError: number;
  43. lastSuccessfulTrade: number;
  44. retryCount: number;
  45. totalRetries: number;
  46. }
  47. class SimpleDeltaNeutralStrategy extends DeltaNeutralVolumeStrategy {
  48. private orderLifecycle: Map<string, OrderLifecycle> = new Map();
  49. private lastApiCall: number = 0;
  50. private apiCallInterval: number = 2000; // 2秒间隔
  51. private orderCheckInterval: NodeJS.Timeout | null = null;
  52. private volumeTradingInterval: NodeJS.Timeout | null = null;
  53. private deltaMonitoringInterval: NodeJS.Timeout | null = null;
  54. private statusDisplayInterval: NodeJS.Timeout | null = null;
  55. private statsSaveInterval: NodeJS.Timeout | null = null;
  56. private healthCheckInterval: NodeJS.Timeout | null = null;
  57. // 账户配对 - Delta中性核心机制
  58. private accountPairs: Array<[Account, Account]> = [];
  59. // 多账户客户端映射 - 每个账户一个客户端
  60. private clientMap: Map<string, PacificaSigningClient> = new Map();
  61. // 账户列表(保存引用用于动态仓位管理)
  62. private strategyAccounts: Account[] = [];
  63. // 风险管理器
  64. private riskManager: RiskManager | null = null;
  65. private sessionId: string;
  66. // 市场数据管理器 - WebSocket实时行情
  67. private marketDataManager: MarketDataManager | null = null;
  68. private currentBTCPrice: number = 0;
  69. private isPriceReady: boolean = false;
  70. // 动态仓位管理器 - 保证金使用率过高时自动减仓
  71. private dynamicPositionManager: DynamicPositionManager | null = null;
  72. // 简洁版统计信息
  73. private stats: SimpleStats = {
  74. totalOrders: 0,
  75. filledOrders: 0,
  76. cancelledOrders: 0,
  77. expiredOrders: 0,
  78. totalVolume: 0,
  79. totalPnL: 0,
  80. startTime: Date.now(),
  81. lastUpdateTime: Date.now(),
  82. consecutiveErrors: 0,
  83. maxConsecutiveErrors: 3,
  84. apiCallCount: 0,
  85. lastApiError: 0,
  86. lastSuccessfulTrade: 0,
  87. retryCount: 0,
  88. totalRetries: 0
  89. };
  90. // 配置参数
  91. private readonly STATS_SAVE_INTERVAL = 600000; // 10分钟保存一次统计
  92. private readonly HEALTH_CHECK_INTERVAL = 300000; // 5分钟健康检查
  93. private readonly MAX_RUNTIME = 6 * 60 * 60 * 1000; // 6小时最大运行时间
  94. private readonly ERROR_RECOVERY_DELAY = 60000; // 60秒错误恢复延迟
  95. private readonly STATS_FILE = './data/simple-stats.json';
  96. private readonly TRADING_PAUSE_DURATION = 120000; // 120秒交易暂停
  97. private readonly MAX_RETRY_ATTEMPTS = 2; // 最大重试次数
  98. private readonly RETRY_DELAY = 10000; // 重试延迟
  99. // 状态控制
  100. private isTradingPaused = false;
  101. private lastTradingPause = 0;
  102. private isInitialized = false;
  103. constructor(
  104. config: DeltaNeutralConfig,
  105. pacificaClient: PacificaSigningClient,
  106. accounts: Account[]
  107. ) {
  108. super(config, pacificaClient, accounts);
  109. this.sessionId = `session_${Date.now()}`;
  110. this.strategyAccounts = accounts; // 保存账户引用
  111. // 为每个账户创建独立的客户端
  112. accounts.forEach(account => {
  113. const client = new PacificaSigningClient(account.getPrivateKey());
  114. this.clientMap.set(account.getId(), client);
  115. });
  116. this.loadStats();
  117. this.initializeRiskManager(config);
  118. this.initializeMarketDataManager();
  119. this.initializeDynamicPositionManager();
  120. }
  121. /**
  122. * 初始化风险管理器
  123. */
  124. private initializeRiskManager(config: DeltaNeutralConfig): void {
  125. const riskConfig: RiskManagerConfig = {
  126. maxTotalVolume: config.maxVolumePositionSize * 10, // 最大总量
  127. maxNetExposure: config.maxDeltaDeviation, // 最大净敞口
  128. maxDailyLoss: config.stopLossThreshold, // 最大每日亏损
  129. positionLimit: config.maxVolumePositionSize, // 仓位限制
  130. stopLossThreshold: config.stopLossThreshold, // 止损阈值
  131. monitoringInterval: 60000 // 60秒监控间隔
  132. };
  133. this.riskManager = new RiskManager(riskConfig);
  134. this.riskManager.on('breach_detected', (breach) => {
  135. this.log(`风险告警: ${breach.type} - ${breach.severity}`, 'error');
  136. if (breach.severity === 'critical') {
  137. this.pauseTrading();
  138. }
  139. });
  140. }
  141. /**
  142. * 初始化市场数据管理器
  143. * 使用WebSocket订阅实时行情,替代REST轮询
  144. */
  145. private initializeMarketDataManager(): void {
  146. this.marketDataManager = new MarketDataManager();
  147. // 监听实时价格更新
  148. this.marketDataManager.on('price_update', (priceData) => {
  149. if (priceData.symbol === 'BTC') {
  150. this.currentBTCPrice = parseFloat(priceData.mark);
  151. if (!this.isPriceReady) {
  152. this.isPriceReady = true;
  153. this.log(`BTC实时价格已就绪: $${this.currentBTCPrice.toFixed(2)}`, 'success');
  154. }
  155. }
  156. });
  157. // 监听WebSocket连接状态
  158. this.marketDataManager.on('connected', () => {
  159. this.log('WebSocket市场数据已连接', 'success');
  160. });
  161. this.marketDataManager.on('disconnected', () => {
  162. this.log('WebSocket市场数据断开,切换到REST轮询', 'warning');
  163. this.isPriceReady = false;
  164. });
  165. }
  166. /**
  167. * 初始化动态仓位管理器
  168. * 当保证金使用率过高时自动减仓
  169. */
  170. private initializeDynamicPositionManager(): void {
  171. // 从配置文件读取设置
  172. let config: PositionAdjustmentConfig;
  173. try {
  174. const strategyConfig = JSON.parse(readFileSync('./config/trading-strategy.json', 'utf-8'));
  175. const posConfig = strategyConfig.dynamicPositionAdjustment;
  176. config = {
  177. enabled: posConfig.enabled ?? true,
  178. maxMarginUsageThreshold: posConfig.maxMarginUsageThreshold ?? 0.85,
  179. targetMarginRelease: posConfig.targetMarginRelease ?? 0.2,
  180. minPositionRatio: posConfig.minPositionRatio ?? 0.3,
  181. checkInterval: posConfig.checkInterval ?? 10000
  182. };
  183. } catch (error) {
  184. // 使用默认配置
  185. config = {
  186. enabled: true,
  187. maxMarginUsageThreshold: 0.85,
  188. targetMarginRelease: 0.2,
  189. minPositionRatio: 0.3,
  190. checkInterval: 10000
  191. };
  192. }
  193. this.dynamicPositionManager = new DynamicPositionManager(config);
  194. this.log('动态仓位管理器已初始化', 'success');
  195. }
  196. /**
  197. * 简洁版日志输出
  198. */
  199. private log(message: string, type: 'info' | 'success' | 'warning' | 'error' = 'info'): void {
  200. const icons = {
  201. info: '📊',
  202. success: '✅',
  203. warning: '⚠️',
  204. error: '❌'
  205. };
  206. // 只显示重要信息,减少时间戳
  207. if (type === 'error' || type === 'success') {
  208. console.log(`${icons[type]} ${message}`);
  209. }
  210. }
  211. /**
  212. * 加载统计信息
  213. */
  214. private loadStats(): void {
  215. try {
  216. if (existsSync(this.STATS_FILE)) {
  217. const savedStats = JSON.parse(readFileSync(this.STATS_FILE, 'utf-8'));
  218. this.stats = { ...this.stats, ...savedStats };
  219. this.log(`加载历史统计: 运行${Math.floor((Date.now() - this.stats.startTime) / 1000 / 60)}分钟`, 'info');
  220. }
  221. } catch (error) {
  222. // 静默处理加载错误
  223. }
  224. }
  225. /**
  226. * 保存统计信息
  227. */
  228. private saveStats(): void {
  229. try {
  230. this.stats.lastUpdateTime = Date.now();
  231. writeFileSync(this.STATS_FILE, JSON.stringify(this.stats, null, 2));
  232. } catch (error) {
  233. // 静默处理保存错误
  234. }
  235. }
  236. /**
  237. * 带重试的API调用
  238. */
  239. private async callApiWithRetry<T>(
  240. apiCall: () => Promise<T>,
  241. operation: string,
  242. maxRetries: number = this.MAX_RETRY_ATTEMPTS
  243. ): Promise<T> {
  244. let lastError: Error | null = null;
  245. for (let attempt = 1; attempt <= maxRetries; attempt++) {
  246. try {
  247. await this.waitForApiCallInterval();
  248. const result = await apiCall();
  249. this.stats.apiCallCount++;
  250. this.stats.retryCount = 0;
  251. return result;
  252. } catch (error) {
  253. lastError = error as Error;
  254. this.stats.retryCount++;
  255. this.stats.totalRetries++;
  256. if (attempt < maxRetries) {
  257. const delay = this.RETRY_DELAY * attempt;
  258. await new Promise(resolve => setTimeout(resolve, delay));
  259. }
  260. }
  261. }
  262. throw lastError;
  263. }
  264. /**
  265. * 健康检查
  266. */
  267. private async performHealthCheck(): Promise<void> {
  268. try {
  269. const runtime = Date.now() - this.stats.startTime;
  270. // 检查最大运行时间
  271. if (runtime > this.MAX_RUNTIME) {
  272. this.log(`达到最大运行时间,准备停止`, 'warning');
  273. await this.stop();
  274. process.exit(0);
  275. }
  276. // 检查连续错误
  277. if (this.stats.consecutiveErrors >= this.stats.maxConsecutiveErrors) {
  278. this.log(`连续错误过多,暂停交易`, 'error');
  279. await this.pauseTrading();
  280. return;
  281. }
  282. // 检查API连接
  283. await this.callApiWithRetry(
  284. () => this.pacificaClient.getPrices(),
  285. '健康检查API连接'
  286. );
  287. // 重置连续错误计数
  288. if (this.stats.consecutiveErrors > 0) {
  289. this.stats.consecutiveErrors = 0;
  290. this.log('API连接恢复', 'success');
  291. }
  292. // 检查交易暂停状态
  293. if (this.isTradingPaused && Date.now() - this.lastTradingPause > this.TRADING_PAUSE_DURATION) {
  294. this.log('恢复交易', 'info');
  295. this.isTradingPaused = false;
  296. }
  297. } catch (error) {
  298. this.stats.consecutiveErrors++;
  299. this.stats.lastApiError = Date.now();
  300. this.log(`健康检查失败`, 'error');
  301. }
  302. }
  303. /**
  304. * 暂停交易
  305. */
  306. private async pauseTrading(): Promise<void> {
  307. this.log('暂停交易,等待错误恢复...', 'warning');
  308. this.isTradingPaused = true;
  309. this.lastTradingPause = Date.now();
  310. // 暂停交易定时器
  311. if (this.volumeTradingInterval) {
  312. clearInterval(this.volumeTradingInterval);
  313. this.volumeTradingInterval = null;
  314. }
  315. // 等待错误恢复
  316. setTimeout(async () => {
  317. this.log('尝试恢复交易...', 'info');
  318. await this.resumeTrading();
  319. }, this.ERROR_RECOVERY_DELAY);
  320. }
  321. /**
  322. * 恢复交易
  323. */
  324. private async resumeTrading(): Promise<void> {
  325. try {
  326. // 重新检查API连接
  327. await this.callApiWithRetry(
  328. () => this.pacificaClient.getPrices(),
  329. '恢复交易API检查'
  330. );
  331. // 恢复交易定时器
  332. this.startVolumeTrading();
  333. this.log('交易恢复成功', 'success');
  334. } catch (error) {
  335. this.log(`交易恢复失败`, 'error');
  336. await this.pauseTrading();
  337. }
  338. }
  339. /**
  340. * 重写开始刷量交易方法
  341. */
  342. protected async startVolumeTrading(): Promise<void> {
  343. this.log('启动简洁版刷量交易系统', 'info');
  344. // 启动订单生命周期管理
  345. this.startOrderLifecycleManagement();
  346. // 启动状态显示
  347. this.startStatusDisplay();
  348. // 启动统计保存
  349. this.startStatsSaving();
  350. // 启动健康检查
  351. this.startHealthCheck();
  352. // 启动动态仓位管理
  353. await this.startDynamicPositionManager();
  354. // 刷量交易 - 15秒间隔
  355. this.volumeTradingInterval = setInterval(async () => {
  356. try {
  357. if (!this.isTradingPaused && this.isInitialized) {
  358. await this.executeVolumeTradingCycle();
  359. }
  360. } catch (error) {
  361. this.stats.consecutiveErrors++;
  362. this.log(`刷量交易失败`, 'warning');
  363. }
  364. }, 15000); // 15秒间隔
  365. // Delta监控 - 120秒间隔
  366. this.deltaMonitoringInterval = setInterval(async () => {
  367. try {
  368. if (this.isInitialized) {
  369. await this.monitorAndRebalance();
  370. }
  371. } catch (error) {
  372. this.stats.consecutiveErrors++;
  373. this.log(`Delta监控失败`, 'warning');
  374. }
  375. }, 120000); // 120秒间隔
  376. }
  377. /**
  378. * 启动订单生命周期管理
  379. */
  380. private startOrderLifecycleManagement(): void {
  381. this.orderCheckInterval = setInterval(async () => {
  382. try {
  383. await this.checkOrderLifecycle();
  384. } catch (error) {
  385. this.stats.consecutiveErrors++;
  386. this.log(`订单检查失败`, 'warning');
  387. }
  388. }, 60000); // 60秒检查一次
  389. }
  390. /**
  391. * 启动状态显示
  392. */
  393. private startStatusDisplay(): void {
  394. this.statusDisplayInterval = setInterval(() => {
  395. this.displayStatus();
  396. }, 600000); // 每10分钟显示一次
  397. }
  398. /**
  399. * 启动统计保存
  400. */
  401. private startStatsSaving(): void {
  402. this.statsSaveInterval = setInterval(() => {
  403. this.saveStats();
  404. }, this.STATS_SAVE_INTERVAL);
  405. }
  406. /**
  407. * 启动健康检查
  408. */
  409. private startHealthCheck(): void {
  410. this.healthCheckInterval = setInterval(async () => {
  411. await this.performHealthCheck();
  412. }, this.HEALTH_CHECK_INTERVAL);
  413. }
  414. /**
  415. * 启动动态仓位管理器
  416. */
  417. private async startDynamicPositionManager(): Promise<void> {
  418. if (!this.dynamicPositionManager) {
  419. console.log('⚠️ 动态仓位管理器未初始化');
  420. return;
  421. }
  422. // 为每个账户初始化管理器
  423. for (const account of this.strategyAccounts) {
  424. const client = this.clientMap.get(account.getId());
  425. if (client) {
  426. this.dynamicPositionManager.initializeAccount(account, client);
  427. console.log(`✅ 为账户 ${account.getName()} 初始化动态仓位管理`);
  428. }
  429. }
  430. // 启动监控
  431. await this.dynamicPositionManager.startMonitoring(this.strategyAccounts);
  432. console.log('✅ 动态仓位管理监控已启动');
  433. this.log('动态仓位管理监控已启动', 'success');
  434. }
  435. /**
  436. * 显示策略状态
  437. */
  438. private displayStatus(): void {
  439. const runtime = Math.floor((Date.now() - this.stats.startTime) / 1000);
  440. const runtimeStr = `${Math.floor(runtime / 3600)}时${Math.floor((runtime % 3600) / 60)}分${runtime % 60}秒`;
  441. console.log('\n' + '='.repeat(50));
  442. console.log('📈 简洁版策略运行状态');
  443. console.log('='.repeat(50));
  444. console.log(`⏰ 运行时间: ${runtimeStr}`);
  445. console.log(`📊 总订单数: ${this.stats.totalOrders}`);
  446. console.log(`✅ 已成交: ${this.stats.filledOrders}`);
  447. console.log(`❌ 已取消: ${this.stats.cancelledOrders}`);
  448. console.log(`📈 总交易量: ${this.stats.totalVolume.toFixed(6)} BTC`);
  449. console.log(`💰 总PNL: ${this.stats.totalPnL.toFixed(2)} USDC`);
  450. console.log(`🔄 活跃订单: ${this.orderLifecycle.size}`);
  451. console.log(`🌐 API调用: ${this.stats.apiCallCount}`);
  452. console.log(`⚠️ 连续错误: ${this.stats.consecutiveErrors}`);
  453. console.log(`⏸️ 交易状态: ${this.isTradingPaused ? '暂停' : '正常'}`);
  454. // 显示WebSocket价格状态
  455. if (this.isPriceReady) {
  456. console.log(`💹 BTC价格: $${this.currentBTCPrice.toFixed(2)} (WebSocket实时)`);
  457. } else {
  458. console.log(`💹 价格源: REST API (WebSocket未就绪)`);
  459. }
  460. // 显示账户配对信息
  461. console.log(`🔗 账户配对: ${this.accountPairs.length}对`);
  462. if (this.stats.totalOrders > 0) {
  463. const successRate = ((this.stats.filledOrders / this.stats.totalOrders) * 100).toFixed(1);
  464. console.log(`🎯 成交率: ${successRate}%`);
  465. }
  466. // 显示健康状态
  467. const healthStatus = this.stats.consecutiveErrors === 0 ? '🟢 健康' : '🔴 异常';
  468. console.log(`🏥 健康状态: ${healthStatus}`);
  469. console.log('='.repeat(50) + '\n');
  470. }
  471. /**
  472. * 检查订单生命周期
  473. */
  474. private async checkOrderLifecycle(): Promise<void> {
  475. const now = Date.now();
  476. const ordersToRemove: string[] = [];
  477. for (const [orderId, order] of this.orderLifecycle) {
  478. try {
  479. // 检查订单是否超时
  480. const timeSinceCreated = now - order.createdAt;
  481. const maxOrderLifetime = 600000; // 600秒最大生命周期
  482. if (timeSinceCreated > maxOrderLifetime) {
  483. this.log(`订单超时取消: ${orderId}`, 'warning');
  484. await this.cancelOrderSafely(orderId, order.symbol);
  485. this.stats.cancelledOrders++;
  486. ordersToRemove.push(orderId);
  487. continue;
  488. }
  489. // 检查订单状态
  490. if (order.status === 'pending' && order.checkCount < order.maxChecks) {
  491. await this.checkOrderStatus(order);
  492. order.checkCount++;
  493. order.lastChecked = now;
  494. }
  495. // 如果检查次数过多,标记为过期
  496. if (order.checkCount >= order.maxChecks) {
  497. this.log(`订单检查超限: ${orderId}`, 'warning');
  498. order.status = 'expired';
  499. this.stats.expiredOrders++;
  500. ordersToRemove.push(orderId);
  501. }
  502. } catch (error) {
  503. this.log(`检查订单失败: ${orderId}`, 'error');
  504. ordersToRemove.push(orderId);
  505. }
  506. }
  507. // 清理过期订单
  508. for (const orderId of ordersToRemove) {
  509. this.orderLifecycle.delete(orderId);
  510. }
  511. }
  512. /**
  513. * 检查单个订单状态
  514. */
  515. private async checkOrderStatus(order: OrderLifecycle): Promise<void> {
  516. try {
  517. const openOrdersResponse = await this.callApiWithRetry(
  518. () => this.pacificaClient.getOpenOrders(),
  519. '检查订单状态'
  520. );
  521. const openOrders = Array.isArray(openOrdersResponse) ? openOrdersResponse : openOrdersResponse.data || [];
  522. const orderExists = openOrders.some((o: any) => o.order_id === parseInt(order.orderId));
  523. if (!orderExists) {
  524. order.status = 'filled';
  525. this.stats.filledOrders++;
  526. this.stats.totalVolume += parseFloat(order.amount);
  527. this.stats.lastSuccessfulTrade = Date.now();
  528. this.log(`订单成交: ${order.side.toUpperCase()} ${order.amount} BTC @ ${order.price}`, 'success');
  529. }
  530. } catch (error) {
  531. this.log(`检查订单状态失败: ${order.orderId}`, 'error');
  532. }
  533. }
  534. /**
  535. * 安全取消订单
  536. */
  537. private async cancelOrderSafely(orderId: string, symbol: string): Promise<void> {
  538. try {
  539. await this.callApiWithRetry(
  540. () => this.pacificaClient.cancelOrder(orderId, symbol),
  541. `取消订单 ${orderId}`
  542. );
  543. } catch (error) {
  544. this.log(`取消订单失败: ${orderId}`, 'error');
  545. }
  546. }
  547. /**
  548. * API调用间隔控制
  549. */
  550. private async waitForApiCallInterval(): Promise<void> {
  551. const now = Date.now();
  552. const timeSinceLastCall = now - this.lastApiCall;
  553. if (timeSinceLastCall < this.apiCallInterval) {
  554. const waitTime = this.apiCallInterval - timeSinceLastCall;
  555. await new Promise(resolve => setTimeout(resolve, waitTime));
  556. }
  557. this.lastApiCall = Date.now();
  558. }
  559. /**
  560. * 重写刷量交易执行
  561. * 优先使用WebSocket实时价格,如果不可用则回退到REST API
  562. */
  563. protected async executeVolumeTrades(): Promise<void> {
  564. try {
  565. // 检查是否应该暂停交易
  566. if (this.isTradingPaused || !this.isInitialized) {
  567. return;
  568. }
  569. let currentPrice: number;
  570. // 优先使用WebSocket实时价格
  571. if (this.isPriceReady && this.currentBTCPrice > 0) {
  572. currentPrice = this.currentBTCPrice;
  573. // 无需API调用,直接使用缓存的实时价格
  574. } else {
  575. // 回退到REST API
  576. this.log('使用REST API获取价格 (WebSocket未就绪)', 'warning');
  577. const prices = await this.callApiWithRetry(
  578. () => this.pacificaClient.getPrices(),
  579. '获取价格信息'
  580. );
  581. const btcPrice = prices.data.find((p: any) => p.symbol === 'BTC');
  582. currentPrice = parseFloat(btcPrice.mark);
  583. }
  584. const totalAccountValue = await this.getTotalAccountValue();
  585. const volumePositionSize = Math.min(
  586. this.config.maxVolumePositionSize,
  587. this.config.volumePositionRatio * totalAccountValue / currentPrice
  588. );
  589. // 使用账户配对执行Delta中性刷量
  590. // 每对账户: 一个买入, 一个卖出, 保证净仓位为零
  591. for (const [buyAccount, sellAccount] of this.accountPairs) {
  592. await this.executePairedVolumeTrade(
  593. buyAccount,
  594. sellAccount,
  595. volumePositionSize,
  596. currentPrice
  597. );
  598. }
  599. } catch (error) {
  600. this.log(`刷量交易失败`, 'warning');
  601. }
  602. }
  603. /**
  604. * 执行配对刷量交易
  605. * 确保买入和卖出同步执行,保持Delta中性
  606. */
  607. private async executePairedVolumeTrade(
  608. buyAccount: Account,
  609. sellAccount: Account,
  610. volumePositionSize: number,
  611. currentPrice: number
  612. ): Promise<void> {
  613. try {
  614. // 计算交易数量 - 满足$10最低订单价值要求
  615. const LOT_SIZE = 0.00001; // BTC最小订单大小 (lot size)
  616. const MIN_ORDER_VALUE = 10; // $10 USDC最低订单价值
  617. // 计算满足$10最低要求的BTC数量
  618. const minBtcAmount = MIN_ORDER_VALUE / currentPrice;
  619. const MIN_ORDER_SIZE = Math.ceil(minBtcAmount / LOT_SIZE) * LOT_SIZE;
  620. let tradeSize = Math.max(
  621. MIN_ORDER_SIZE,
  622. Math.min(
  623. volumePositionSize * 0.5, // 每次交易50%的刷量仓位
  624. this.config.maxVolumePositionSize // 最大刷量仓位
  625. )
  626. );
  627. // 确保是lot size的整数倍
  628. tradeSize = Math.floor(tradeSize / LOT_SIZE) * LOT_SIZE;
  629. tradeSize = Math.max(tradeSize, MIN_ORDER_SIZE);
  630. // 验证订单价值
  631. const orderValue = tradeSize * currentPrice;
  632. if (orderValue < MIN_ORDER_VALUE) {
  633. this.log(`订单价值过低: $${orderValue.toFixed(2)} < $10, 跳过`, 'warning');
  634. return;
  635. }
  636. // 余额检查
  637. const buyClient = this.clientMap.get(buyAccount.getId());
  638. const sellClient = this.clientMap.get(sellAccount.getId());
  639. if (!buyClient || !sellClient) {
  640. this.log('账户客户端未找到,跳过交易', 'warning');
  641. return;
  642. }
  643. // 检查买入账户余额
  644. const buyBalance = await this.checkAccountBalance(buyAccount, buyClient, orderValue);
  645. if (!buyBalance) {
  646. this.log(`买入账户余额不足: ${buyAccount.getId().slice(0,8)}`, 'warning');
  647. this.handleInsufficientBalance();
  648. return;
  649. }
  650. // 检查卖出账户是否有足够的BTC
  651. const sellBalance = await this.checkAccountBalance(sellAccount, sellClient, tradeSize, true);
  652. if (!sellBalance) {
  653. this.log(`卖出账户BTC不足: ${sellAccount.getId().slice(0,8)}`, 'warning');
  654. this.handleInsufficientBalance();
  655. return;
  656. }
  657. // 风险检查 - 在执行交易前检查仓位大小
  658. if (this.riskManager) {
  659. const buyRiskBreach = await this.riskManager.checkPositionSizeRisk(
  660. this.sessionId,
  661. buyAccount.getId(),
  662. tradeSize
  663. );
  664. const sellRiskBreach = await this.riskManager.checkPositionSizeRisk(
  665. this.sessionId,
  666. sellAccount.getId(),
  667. tradeSize
  668. );
  669. if (buyRiskBreach || sellRiskBreach) {
  670. this.log(`风险检查未通过,跳过本次交易`, 'warning');
  671. return;
  672. }
  673. }
  674. // 同步执行买入和卖出订单 - 这是Delta中性的关键
  675. await Promise.all([
  676. this.executeAccountVolumeTradeWithLifecycle(buyAccount, tradeSize, currentPrice, 'bid'),
  677. this.executeAccountVolumeTradeWithLifecycle(sellAccount, tradeSize, currentPrice, 'ask')
  678. ]);
  679. this.log(`配对交易: ${buyAccount.getId().slice(0,8)}买/${sellAccount.getId().slice(0,8)}卖`, 'success');
  680. } catch (error) {
  681. this.log(`配对交易失败: ${buyAccount.getId().slice(0,8)} <-> ${sellAccount.getId().slice(0,8)}`, 'warning');
  682. }
  683. }
  684. /**
  685. * 带生命周期管理的账户刷量交易
  686. * @param side - 'bid' (买入) 或 'ask' (卖出), 由配对机制指定
  687. */
  688. private async executeAccountVolumeTradeWithLifecycle(
  689. account: Account,
  690. tradeSize: number,
  691. currentPrice: number,
  692. side: 'bid' | 'ask'
  693. ): Promise<void> {
  694. try {
  695. // 获取账户专属客户端
  696. const client = this.clientMap.get(account.getId());
  697. if (!client) {
  698. this.log(`账户客户端未找到: ${account.getId()}`, 'error');
  699. return;
  700. }
  701. // 智能选择订单类型
  702. if (this.config.preferredOrderType === 'limit') {
  703. await this.createLimitOrderWithLifecycle(account, client, side, tradeSize, currentPrice);
  704. } else {
  705. await this.createVolumeMarketOrder(account, client, side, tradeSize);
  706. }
  707. } catch (error) {
  708. this.log(`账户交易失败: ${account.getId()} (${side})`, 'warning');
  709. }
  710. }
  711. /**
  712. * 创建带生命周期管理的limit订单(优先限价单降低手续费)
  713. */
  714. private async createLimitOrderWithLifecycle(
  715. account: Account,
  716. client: PacificaSigningClient,
  717. side: 'bid' | 'ask',
  718. amount: number,
  719. currentPrice: number
  720. ): Promise<void> {
  721. try {
  722. // 使用更小的价差提高成交率
  723. const spread = this.config.limitOrderSpread;
  724. const price = side === 'bid'
  725. ? (currentPrice * (1 - spread)).toFixed(0)
  726. : (currentPrice * (1 + spread)).toFixed(0);
  727. const clientOrderId = uuidv4();
  728. const order = {
  729. symbol: 'BTC',
  730. amount: amount.toFixed(8),
  731. side,
  732. price,
  733. tif: 'GTC', // Good-Till-Cancel (挂单等待成交)
  734. reduce_only: false,
  735. client_order_id: clientOrderId
  736. };
  737. const result = await this.callApiWithRetry(
  738. () => client.createLimitOrder(order),
  739. `创建${side}订单 (${account.getId().slice(0,8)})`
  740. );
  741. if (result.success && result.data?.order_id) {
  742. const orderId = result.data.order_id.toString();
  743. // 创建订单生命周期记录 - 10秒超时
  744. const orderLifecycle: OrderLifecycle = {
  745. orderId,
  746. clientOrderId,
  747. accountId: account.getId(), // 记录账户ID
  748. symbol: 'BTC',
  749. side,
  750. amount: order.amount,
  751. price: order.price,
  752. status: 'pending',
  753. createdAt: Date.now(),
  754. lastChecked: Date.now(),
  755. checkCount: 0,
  756. maxChecks: 1 // 10秒超时(检查1次后转市价单)
  757. };
  758. this.orderLifecycle.set(orderId, orderLifecycle);
  759. this.stats.totalOrders++;
  760. this.log(`限价单: ${side.toUpperCase()} ${amount.toFixed(6)} BTC @ $${price} (${account.getId().slice(0,8)})`, 'info');
  761. // 启动订单监控(如果还未启动)
  762. if (!this.orderCheckInterval) {
  763. this.startOrderMonitoring();
  764. }
  765. }
  766. } catch (error) {
  767. this.log(`限价单失败: ${side}, 降级为市价单`, 'warning');
  768. // 限价单失败,降级为市价单
  769. await this.createVolumeMarketOrder(account, client, side, amount);
  770. }
  771. }
  772. /**
  773. * 启动订单状态监控
  774. */
  775. private startOrderMonitoring(): void {
  776. this.orderCheckInterval = setInterval(async () => {
  777. await this.checkPendingOrders();
  778. }, 10000); // 每10秒检查一次
  779. this.log('订单监控已启动 (10秒间隔)', 'info');
  780. }
  781. /**
  782. * 检查待处理订单状态
  783. */
  784. private async checkPendingOrders(): Promise<void> {
  785. const now = Date.now();
  786. const ordersToCheck = Array.from(this.orderLifecycle.entries())
  787. .filter(([_, order]) => order.status === 'pending');
  788. for (const [orderId, order] of ordersToCheck) {
  789. try {
  790. order.checkCount++;
  791. order.lastChecked = now;
  792. // 检查是否超时
  793. const ageSeconds = (now - order.createdAt) / 1000;
  794. if (order.checkCount >= order.maxChecks) {
  795. // 超时未成交,撤单并使用市价单重试
  796. this.log(`限价单超时 (${ageSeconds.toFixed(0)}s): ${order.side.toUpperCase()} @ $${order.price}, 转市价单`, 'warning');
  797. await this.cancelAndRetryWithMarket(orderId, order);
  798. }
  799. } catch (error) {
  800. this.log(`检查订单${orderId}失败`, 'warning');
  801. }
  802. }
  803. }
  804. /**
  805. * 撤单并使用市价单重试
  806. */
  807. private async cancelAndRetryWithMarket(orderId: string, order: OrderLifecycle): Promise<void> {
  808. try {
  809. // 使用订单记录中的账户ID找到正确的账户和客户端
  810. const targetAccount = this.accounts.find(acc => acc.getId() === order.accountId);
  811. const targetClient = targetAccount ? this.clientMap.get(targetAccount.getId()) : null;
  812. if (!targetAccount || !targetClient) {
  813. this.log(`找不到订单对应的账户: ${order.accountId.slice(0,8)}`, 'error');
  814. return;
  815. }
  816. // 尝试撤销订单
  817. try {
  818. await targetClient.cancelOrder(orderId, 'BTC');
  819. this.log(`已撤销限价单: ${orderId} (${targetAccount.getId().slice(0,8)})`, 'info');
  820. } catch (error) {
  821. // 订单可能已成交或不存在,忽略错误
  822. this.log(`撤单失败(可能已成交): ${orderId}`, 'warning');
  823. }
  824. // 标记为已取消
  825. order.status = 'cancelled';
  826. this.stats.cancelledOrders++;
  827. // 使用市价单重试相同数量
  828. const amount = parseFloat(order.amount);
  829. this.log(`市价单重试: ${order.side.toUpperCase()} ${amount.toFixed(6)} BTC (${targetAccount.getId().slice(0,8)})`, 'info');
  830. await this.createVolumeMarketOrder(
  831. targetAccount,
  832. targetClient,
  833. order.side,
  834. amount
  835. );
  836. } catch (error) {
  837. this.log(`撤单重试失败: ${orderId}`, 'error');
  838. }
  839. }
  840. /**
  841. * 创建市场订单
  842. */
  843. private async createVolumeMarketOrder(
  844. account: Account,
  845. client: PacificaSigningClient,
  846. side: 'bid' | 'ask',
  847. amount: number
  848. ): Promise<void> {
  849. try {
  850. const clientOrderId = uuidv4();
  851. const order = {
  852. symbol: 'BTC',
  853. amount: amount.toFixed(8),
  854. side,
  855. slippage_percent: '0.5',
  856. reduce_only: false,
  857. client_order_id: clientOrderId
  858. };
  859. const result = await this.callApiWithRetry(
  860. () => client.createMarketOrder(order),
  861. `创建市场${side}订单 (${account.getId().slice(0,8)})`
  862. );
  863. if (result.success && result.data?.order_id) {
  864. const orderId = result.data.order_id.toString();
  865. const orderLifecycle: OrderLifecycle = {
  866. orderId,
  867. clientOrderId,
  868. accountId: account.getId(), // 记录账户ID
  869. symbol: 'BTC',
  870. side,
  871. amount: order.amount,
  872. price: '0', // market order has no fixed price
  873. status: 'pending',
  874. createdAt: Date.now(),
  875. lastChecked: Date.now(),
  876. checkCount: 0,
  877. maxChecks: 10
  878. };
  879. this.orderLifecycle.set(orderId, orderLifecycle);
  880. this.stats.totalOrders++;
  881. this.log(`创建市场订单: ${side.toUpperCase()} ${amount.toFixed(6)} BTC (${account.getId().slice(0,8)})`, 'info');
  882. }
  883. } catch (error) {
  884. this.log(`创建市场订单失败: ${side}`, 'error');
  885. }
  886. }
  887. /**
  888. * 重写初始化方法 - 完全自定义,不调用父类
  889. */
  890. public async initialize(): Promise<void> {
  891. try {
  892. this.log('开始初始化简洁版策略...', 'info');
  893. // 初始化账户配对 - Delta中性核心
  894. this.initializeAccountPairs();
  895. // 初始化并启动市场数据管理器
  896. if (this.marketDataManager) {
  897. await this.marketDataManager.initialize();
  898. this.log('市场数据管理器已启动 (WebSocket)', 'success');
  899. // 等待初始价格数据 (最多5秒)
  900. const priceTimeout = setTimeout(() => {
  901. if (!this.isPriceReady) {
  902. this.log('WebSocket价格未就绪,将使用REST API后备', 'warning');
  903. }
  904. }, 5000);
  905. // 等待价格就绪或超时
  906. for (let i = 0; i < 50 && !this.isPriceReady; i++) {
  907. await new Promise(resolve => setTimeout(resolve, 100));
  908. }
  909. clearTimeout(priceTimeout);
  910. }
  911. // 初始化并启动风险管理器
  912. if (this.riskManager) {
  913. await this.riskManager.initialize();
  914. await this.riskManager.startMonitoring(this.sessionId);
  915. this.log('风险管理器已启动', 'success');
  916. }
  917. // 启动配对刷量交易循环
  918. this.startPairedVolumeTrading();
  919. // 启动Delta再平衡监控
  920. this.startDeltaRebalancing();
  921. // 启动动态仓位管理器
  922. await this.startDynamicPositionManager();
  923. this.isInitialized = true;
  924. this.log('简洁版策略初始化成功', 'success');
  925. } catch (error) {
  926. this.log(`策略初始化失败`, 'error');
  927. throw error;
  928. }
  929. }
  930. /**
  931. * 启动配对刷量交易
  932. */
  933. private startPairedVolumeTrading(): void {
  934. // 启动刷量交易循环 - 每10秒执行一次
  935. this.volumeTradingInterval = setInterval(async () => {
  936. if (this.isTradingPaused) {
  937. return;
  938. }
  939. try {
  940. await this.executeVolumeTrades();
  941. } catch (error) {
  942. this.log('刷量交易周期失败', 'warning');
  943. }
  944. }, 10000);
  945. this.log('配对刷量交易已启动 (10秒间隔)', 'success');
  946. }
  947. /**
  948. * 启动Delta再平衡监控
  949. * 定期检查并修正仓位不平衡
  950. */
  951. private startDeltaRebalancing(): void {
  952. // 每60秒检查一次Delta平衡
  953. this.deltaMonitoringInterval = setInterval(async () => {
  954. if (this.isTradingPaused) {
  955. return;
  956. }
  957. try {
  958. await this.checkAndRebalanceDelta();
  959. } catch (error) {
  960. this.log('Delta再平衡检查失败', 'warning');
  961. }
  962. }, 60000);
  963. this.log('Delta再平衡监控已启动 (60秒间隔)', 'success');
  964. }
  965. /**
  966. * 检查并执行Delta再平衡
  967. */
  968. private async checkAndRebalanceDelta(): Promise<void> {
  969. try {
  970. // 获取所有账户的实时仓位
  971. const positions = await this.getAllAccountPositions();
  972. if (positions.length === 0) {
  973. return;
  974. }
  975. // 计算总净Delta
  976. let totalNetDelta = 0;
  977. let totalExposure = 0;
  978. for (const pos of positions) {
  979. totalNetDelta += pos.netPosition;
  980. totalExposure += Math.abs(pos.netPosition);
  981. }
  982. // 如果没有仓位,无需再平衡
  983. if (totalExposure === 0) {
  984. return;
  985. }
  986. // 计算Delta偏差百分比
  987. const deltaDeviationPercent = Math.abs(totalNetDelta / totalExposure);
  988. this.log(`Delta状态: 净Delta=${totalNetDelta.toFixed(8)} BTC, 偏差=${(deltaDeviationPercent * 100).toFixed(2)}%`, 'info');
  989. // 如果偏差超过阈值(例如5%),触发再平衡
  990. const REBALANCE_THRESHOLD = 0.05; // 5%阈值
  991. if (deltaDeviationPercent > REBALANCE_THRESHOLD) {
  992. this.log(`⚠️ Delta偏差过大 (${(deltaDeviationPercent * 100).toFixed(2)}%), 开始再平衡...`, 'warning');
  993. await this.executeDeltaRebalance(positions, totalNetDelta);
  994. }
  995. } catch (error) {
  996. this.log('Delta再平衡执行失败', 'error');
  997. }
  998. }
  999. /**
  1000. * 获取所有账户的实时仓位
  1001. */
  1002. private async getAllAccountPositions(): Promise<Array<{account: Account, client: PacificaSigningClient, netPosition: number, amount: string, side: string}>> {
  1003. const positions = [];
  1004. for (const account of this.accounts) {
  1005. const client = this.clientMap.get(account.getId());
  1006. if (!client) {
  1007. continue;
  1008. }
  1009. try {
  1010. const result = await client.getAccountPositions();
  1011. if (result.data && Array.isArray(result.data)) {
  1012. const btcPos = result.data.find((p: any) => p.symbol === 'BTC');
  1013. if (btcPos) {
  1014. // bid = long (正), ask = short (负)
  1015. const netPosition = btcPos.side === 'bid'
  1016. ? parseFloat(btcPos.amount)
  1017. : -parseFloat(btcPos.amount);
  1018. positions.push({
  1019. account,
  1020. client,
  1021. netPosition,
  1022. amount: btcPos.amount,
  1023. side: btcPos.side
  1024. });
  1025. }
  1026. }
  1027. } catch (error) {
  1028. this.log(`获取账户${account.getId().slice(0,8)}仓位失败`, 'warning');
  1029. }
  1030. }
  1031. return positions;
  1032. }
  1033. /**
  1034. * 执行Delta再平衡
  1035. * 通过调整账户仓位使净Delta接近零
  1036. */
  1037. private async executeDeltaRebalance(
  1038. positions: Array<{account: Account, client: PacificaSigningClient, netPosition: number, amount: string, side: string}>,
  1039. totalNetDelta: number
  1040. ): Promise<void> {
  1041. try {
  1042. // 计算需要平衡的数量(净Delta的一半,分配到两个方向)
  1043. const rebalanceAmount = Math.abs(totalNetDelta) / 2;
  1044. // 确保满足最小订单要求
  1045. const LOT_SIZE = 0.00001;
  1046. const MIN_ORDER_VALUE = 10;
  1047. const currentPrice = this.currentBTCPrice || 113000;
  1048. const minBtcAmount = MIN_ORDER_VALUE / currentPrice;
  1049. const MIN_ORDER_SIZE = Math.ceil(minBtcAmount / LOT_SIZE) * LOT_SIZE;
  1050. let adjustedRebalanceAmount = Math.floor(rebalanceAmount / LOT_SIZE) * LOT_SIZE;
  1051. if (adjustedRebalanceAmount < MIN_ORDER_SIZE) {
  1052. this.log(`再平衡数量过小 (${adjustedRebalanceAmount.toFixed(8)} < ${MIN_ORDER_SIZE.toFixed(8)}), 跳过`, 'info');
  1053. return;
  1054. }
  1055. // 找出净多头和净空头账户
  1056. const longPositions = positions.filter(p => p.netPosition > 0);
  1057. const shortPositions = positions.filter(p => p.netPosition < 0);
  1058. if (totalNetDelta > 0) {
  1059. // 净多头过多:减少多头仓位,增加空头仓位
  1060. this.log(`执行再平衡: 减少${adjustedRebalanceAmount.toFixed(8)} BTC多头`, 'info');
  1061. // 在最大多头账户上减仓
  1062. if (longPositions.length > 0) {
  1063. const maxLongAccount = longPositions.reduce((max, p) =>
  1064. p.netPosition > max.netPosition ? p : max
  1065. );
  1066. await this.executeRebalanceOrder(
  1067. maxLongAccount.account,
  1068. maxLongAccount.client,
  1069. adjustedRebalanceAmount,
  1070. 'ask' // 平多头 = 卖出
  1071. );
  1072. }
  1073. // 在最小空头账户上加仓
  1074. if (shortPositions.length > 0) {
  1075. const minShortAccount = shortPositions.reduce((min, p) =>
  1076. Math.abs(p.netPosition) < Math.abs(min.netPosition) ? p : min
  1077. );
  1078. await this.executeRebalanceOrder(
  1079. minShortAccount.account,
  1080. minShortAccount.client,
  1081. adjustedRebalanceAmount,
  1082. 'ask' // 增加空头 = 卖出
  1083. );
  1084. } else {
  1085. // 如果没有空头账户,在另一个多头账户上开空
  1086. if (longPositions.length > 1) {
  1087. const minLongAccount = longPositions.reduce((min, p) =>
  1088. p.netPosition < min.netPosition ? p : min
  1089. );
  1090. await this.executeRebalanceOrder(
  1091. minLongAccount.account,
  1092. minLongAccount.client,
  1093. adjustedRebalanceAmount,
  1094. 'ask'
  1095. );
  1096. }
  1097. }
  1098. } else {
  1099. // 净空头过多:减少空头仓位,增加多头仓位
  1100. this.log(`执行再平衡: 减少${adjustedRebalanceAmount.toFixed(8)} BTC空头`, 'info');
  1101. // 在最大空头账户上减仓
  1102. if (shortPositions.length > 0) {
  1103. const maxShortAccount = shortPositions.reduce((max, p) =>
  1104. Math.abs(p.netPosition) > Math.abs(max.netPosition) ? p : max
  1105. );
  1106. await this.executeRebalanceOrder(
  1107. maxShortAccount.account,
  1108. maxShortAccount.client,
  1109. adjustedRebalanceAmount,
  1110. 'bid' // 平空头 = 买入
  1111. );
  1112. }
  1113. // 在最小多头账户上加仓
  1114. if (longPositions.length > 0) {
  1115. const minLongAccount = longPositions.reduce((min, p) =>
  1116. p.netPosition < min.netPosition ? p : min
  1117. );
  1118. await this.executeRebalanceOrder(
  1119. minLongAccount.account,
  1120. minLongAccount.client,
  1121. adjustedRebalanceAmount,
  1122. 'bid' // 增加多头 = 买入
  1123. );
  1124. } else {
  1125. // 如果没有多头账户,在另一个空头账户上开多
  1126. if (shortPositions.length > 1) {
  1127. const minShortAccount = shortPositions.reduce((min, p) =>
  1128. Math.abs(p.netPosition) < Math.abs(min.netPosition) ? p : min
  1129. );
  1130. await this.executeRebalanceOrder(
  1131. minShortAccount.account,
  1132. minShortAccount.client,
  1133. adjustedRebalanceAmount,
  1134. 'bid'
  1135. );
  1136. }
  1137. }
  1138. }
  1139. this.log('✅ Delta再平衡完成', 'success');
  1140. } catch (error) {
  1141. this.log('Delta再平衡执行失败', 'error');
  1142. }
  1143. }
  1144. /**
  1145. * 执行再平衡订单
  1146. */
  1147. private async executeRebalanceOrder(
  1148. account: Account,
  1149. client: PacificaSigningClient,
  1150. amount: number,
  1151. side: 'bid' | 'ask'
  1152. ): Promise<void> {
  1153. try {
  1154. const clientOrderId = uuidv4();
  1155. const order = {
  1156. symbol: 'BTC',
  1157. amount: amount.toFixed(8),
  1158. side,
  1159. slippage_percent: '0.5',
  1160. reduce_only: false,
  1161. client_order_id: clientOrderId
  1162. };
  1163. const result = await this.callApiWithRetry(
  1164. () => client.createMarketOrder(order),
  1165. `再平衡订单 (${account.getId().slice(0,8)} ${side})`
  1166. );
  1167. if (result.success) {
  1168. this.log(`✅ 再平衡订单: ${account.getId().slice(0,8)} ${side.toUpperCase()} ${amount.toFixed(8)} BTC`, 'success');
  1169. }
  1170. } catch (error) {
  1171. this.log(`再平衡订单失败: ${account.getId().slice(0,8)} ${side}`, 'error');
  1172. }
  1173. }
  1174. /**
  1175. * 初始化账户配对机制
  1176. * 确保Delta中性: 每个买单都有对应的卖单
  1177. */
  1178. private initializeAccountPairs(): void {
  1179. if (this.accounts.length < 2) {
  1180. throw new Error('需要至少2个账户进行Delta中性对冲');
  1181. }
  1182. if (this.accounts.length % 2 !== 0) {
  1183. this.log(`警告: 账户数量为奇数(${this.accounts.length}), 最后一个账户将不参与配对`, 'warning');
  1184. }
  1185. this.accountPairs = [];
  1186. for (let i = 0; i < this.accounts.length - 1; i += 2) {
  1187. this.accountPairs.push([this.accounts[i], this.accounts[i + 1]]);
  1188. }
  1189. this.log(`账户配对完成: ${this.accountPairs.length}对账户`, 'success');
  1190. this.accountPairs.forEach((pair, index) => {
  1191. this.log(` 配对${index + 1}: ${pair[0].getId()} (买) <-> ${pair[1].getId()} (卖)`, 'info');
  1192. });
  1193. }
  1194. /**
  1195. * 检查账户余额
  1196. * @param account 账户
  1197. * @param client 客户端
  1198. * @param requiredAmount 需要的金额(USDC或BTC)
  1199. * @param isBTC 是否检查BTC余额
  1200. */
  1201. private async checkAccountBalance(
  1202. account: Account,
  1203. client: PacificaSigningClient,
  1204. requiredAmount: number,
  1205. isBTC: boolean = false
  1206. ): Promise<boolean> {
  1207. try {
  1208. const accountInfo = await client.getAccountInfo();
  1209. if (isBTC) {
  1210. // 检查BTC持仓
  1211. const positions = await client.getAccountPositions();
  1212. const btcPositions = Array.isArray(positions.data) ?
  1213. positions.data.filter((p: any) => p.symbol === 'BTC') : [];
  1214. const totalBTC = btcPositions.reduce((sum: number, p: any) => {
  1215. return sum + Math.abs(parseFloat(p.amount));
  1216. }, 0);
  1217. return totalBTC >= requiredAmount;
  1218. } else {
  1219. // 检查USDC余额
  1220. const availableBalance = parseFloat(accountInfo.data.available_to_spend);
  1221. const marginBuffer = 1.1; // 10%缓冲
  1222. return availableBalance >= requiredAmount * marginBuffer;
  1223. }
  1224. } catch (error) {
  1225. this.log(`检查余额失败: ${account.getId().slice(0,8)}`, 'error');
  1226. return false;
  1227. }
  1228. }
  1229. /**
  1230. * 处理余额不足
  1231. */
  1232. private handleInsufficientBalance(): void {
  1233. if (!this.insufficientBalanceCount) {
  1234. this.insufficientBalanceCount = 0;
  1235. }
  1236. this.insufficientBalanceCount++;
  1237. // 如果连续5次余额不足,暂停交易
  1238. if (this.insufficientBalanceCount >= 5) {
  1239. this.log('⚠️ 连续余额不足,暂停交易60秒', 'warning');
  1240. this.isTradingPaused = true;
  1241. // 60秒后恢复
  1242. setTimeout(() => {
  1243. this.isTradingPaused = false;
  1244. this.insufficientBalanceCount = 0;
  1245. this.log('✅ 恢复交易', 'success');
  1246. }, 60000);
  1247. }
  1248. }
  1249. private insufficientBalanceCount: number = 0;
  1250. /**
  1251. * 重写停止方法
  1252. */
  1253. public async stop(): Promise<void> {
  1254. this.log('停止简洁版策略...', 'info');
  1255. // 清理定时器
  1256. if (this.volumeTradingInterval) {
  1257. clearInterval(this.volumeTradingInterval);
  1258. this.volumeTradingInterval = null;
  1259. }
  1260. if (this.deltaMonitoringInterval) {
  1261. clearInterval(this.deltaMonitoringInterval);
  1262. this.deltaMonitoringInterval = null;
  1263. }
  1264. if (this.orderCheckInterval) {
  1265. clearInterval(this.orderCheckInterval);
  1266. this.orderCheckInterval = null;
  1267. }
  1268. if (this.statusDisplayInterval) {
  1269. clearInterval(this.statusDisplayInterval);
  1270. this.statusDisplayInterval = null;
  1271. }
  1272. if (this.statsSaveInterval) {
  1273. clearInterval(this.statsSaveInterval);
  1274. this.statsSaveInterval = null;
  1275. }
  1276. if (this.healthCheckInterval) {
  1277. clearInterval(this.healthCheckInterval);
  1278. this.healthCheckInterval = null;
  1279. }
  1280. // 停止动态仓位管理器
  1281. if (this.dynamicPositionManager) {
  1282. this.dynamicPositionManager.shutdown();
  1283. this.log('动态仓位管理器已停止', 'success');
  1284. }
  1285. // 使用 OrderCleanupService 取消所有开放订单
  1286. console.log('\n🧹 正在从 Pacifica API 获取开放订单...');
  1287. this.log('清理所有开放订单...', 'info');
  1288. try {
  1289. const cleanupService = new OrderCleanupService();
  1290. // 为每个账户初始化清理服务
  1291. for (const account of this.accounts) {
  1292. cleanupService.initializeAccount(account);
  1293. }
  1294. // 强制清理所有订单
  1295. const cleanupOptions: CleanupOptions = {
  1296. cleanAll: true,
  1297. includeReduceOnly: true, // 包括保护性订单
  1298. mode: 'force', // 强制模式
  1299. dryRun: false
  1300. };
  1301. console.log('从 API 获取订单并取消...');
  1302. const results = await cleanupService.cleanupMultipleAccounts(
  1303. this.accounts,
  1304. cleanupOptions
  1305. );
  1306. // 汇总清理结果
  1307. let totalOrders = 0;
  1308. let totalCancelled = 0;
  1309. for (const result of results.values()) {
  1310. totalOrders += result.totalOrders;
  1311. totalCancelled += result.cancelledOrders;
  1312. }
  1313. console.log(`📊 从 API 获取到 ${totalOrders} 个开放订单`);
  1314. if (totalCancelled > 0) {
  1315. console.log(`✅ 已取消 ${totalCancelled} 个开放订单`);
  1316. this.log(`已取消 ${totalCancelled} 个开放订单`, 'success');
  1317. } else {
  1318. console.log('✅ 没有需要清理的订单');
  1319. this.log('没有需要清理的订单', 'info');
  1320. }
  1321. await cleanupService.shutdown();
  1322. } catch (error) {
  1323. this.log('⚠️ 订单清理失败,尝试手动取消', 'warning');
  1324. // 降级处理:手动取消内存中的订单
  1325. for (const [orderId, order] of this.orderLifecycle) {
  1326. if (order.status === 'pending') {
  1327. try {
  1328. await this.cancelOrderSafely(orderId, order.symbol);
  1329. } catch (error) {
  1330. this.log(`取消订单失败: ${orderId}`, 'error');
  1331. }
  1332. }
  1333. }
  1334. }
  1335. // 清理生命周期记录
  1336. this.orderLifecycle.clear();
  1337. // 停止市场数据管理器
  1338. if (this.marketDataManager) {
  1339. await this.marketDataManager.disconnect();
  1340. this.log('市场数据管理器已停止', 'info');
  1341. }
  1342. // 停止风险管理器
  1343. if (this.riskManager) {
  1344. await this.riskManager.stopMonitoring(this.sessionId);
  1345. await this.riskManager.shutdown();
  1346. this.log('风险管理器已停止', 'info');
  1347. }
  1348. // 保存最终统计
  1349. this.saveStats();
  1350. // 显示最终统计
  1351. this.displayFinalStats();
  1352. // 调用父类停止方法
  1353. await super.stop();
  1354. this.log('简洁版策略已停止', 'success');
  1355. }
  1356. /**
  1357. * 显示最终统计
  1358. */
  1359. private displayFinalStats(): void {
  1360. const runtime = Math.floor((Date.now() - this.stats.startTime) / 1000);
  1361. const runtimeStr = `${Math.floor(runtime / 3600)}时${Math.floor((runtime % 3600) / 60)}分${runtime % 60}秒`;
  1362. console.log('\n' + '='.repeat(50));
  1363. console.log('📊 简洁版策略最终统计');
  1364. console.log('='.repeat(50));
  1365. console.log(`⏰ 总运行时间: ${runtimeStr}`);
  1366. console.log(`📊 总订单数: ${this.stats.totalOrders}`);
  1367. console.log(`✅ 已成交: ${this.stats.filledOrders}`);
  1368. console.log(`❌ 已取消: ${this.stats.cancelledOrders}`);
  1369. console.log(`📈 总交易量: ${this.stats.totalVolume.toFixed(6)} BTC`);
  1370. console.log(`💰 总PNL: ${this.stats.totalPnL.toFixed(2)} USDC`);
  1371. console.log(`🌐 API调用: ${this.stats.apiCallCount}`);
  1372. console.log(`🔄 总重试次数: ${this.stats.totalRetries}`);
  1373. console.log(`⚠️ 最大连续错误: ${this.stats.consecutiveErrors}`);
  1374. if (this.stats.totalOrders > 0) {
  1375. const successRate = ((this.stats.filledOrders / this.stats.totalOrders) * 100).toFixed(1);
  1376. const avgVolume = (this.stats.totalVolume / this.stats.filledOrders).toFixed(6);
  1377. console.log(`🎯 成交率: ${successRate}%`);
  1378. console.log(`📊 平均交易量: ${avgVolume} BTC`);
  1379. }
  1380. console.log('='.repeat(50) + '\n');
  1381. }
  1382. }
  1383. async function runSimpleDeltaNeutralStrategy() {
  1384. console.log('🚀 启动简洁版Delta中性刷量策略...\n');
  1385. try {
  1386. // 1. 加载配置
  1387. console.log('📋 加载配置文件...');
  1388. const accountsConfig = JSON.parse(readFileSync('./config/accounts.json', 'utf-8'));
  1389. const strategyConfig = JSON.parse(readFileSync('./config/trading-strategy.json', 'utf-8'));
  1390. console.log(`✅ 账户配置: ${accountsConfig.length} 个账户`);
  1391. console.log(`✅ 策略配置: ${strategyConfig.orderStrategy.preferredOrderType}单优先`);
  1392. // 2. 初始化Pacifica客户端
  1393. console.log('\n🔗 初始化Pacifica客户端...');
  1394. const privateKey = accountsConfig[0].privateKey;
  1395. const pacificaClient = new PacificaSigningClient(privateKey);
  1396. console.log('✅ Pacifica客户端初始化成功');
  1397. console.log(`公钥: ${pacificaClient.getPublicKey()}`);
  1398. // 3. 获取当前市场信息(带重试)
  1399. console.log('\n📊 获取当前市场信息...');
  1400. let prices, marketInfo, accountInfo;
  1401. let retryCount = 0;
  1402. const maxRetries = 3;
  1403. while (retryCount < maxRetries) {
  1404. try {
  1405. prices = await pacificaClient.getPrices();
  1406. marketInfo = await pacificaClient.getMarketInfo();
  1407. accountInfo = await pacificaClient.getAccountInfo();
  1408. break;
  1409. } catch (error) {
  1410. retryCount++;
  1411. console.log(`⚠️ 获取市场信息失败 (尝试 ${retryCount}/${maxRetries})`);
  1412. if (retryCount < maxRetries) {
  1413. const delay = 10000 * retryCount;
  1414. console.log(`等待 ${delay/1000} 秒后重试...`);
  1415. await new Promise(resolve => setTimeout(resolve, delay));
  1416. } else {
  1417. throw error;
  1418. }
  1419. }
  1420. }
  1421. const btcPrice = prices.data.find((p: any) => p.symbol === 'BTC');
  1422. const btcMarket = marketInfo.data.find((m: any) => m.symbol === 'BTC');
  1423. const currentPrice = parseFloat(btcPrice.mark);
  1424. const accountBalance = parseFloat(accountInfo.data.balance);
  1425. const minOrderSize = parseFloat(btcMarket.min_order_size);
  1426. const lotSize = parseFloat(btcMarket.lot_size);
  1427. console.log('✅ 市场信息获取成功');
  1428. console.log(`BTC当前价格: ${currentPrice}`);
  1429. console.log(`账户余额: ${accountBalance} USDC`);
  1430. console.log(`最小订单大小: ${minOrderSize} USDC`);
  1431. // 4. 计算仓位大小(基于配置)
  1432. console.log('\n💰 计算仓位大小...');
  1433. const minOrderValue = Math.max(minOrderSize, strategyConfig.positions.minOrderValue);
  1434. const availableBalance = accountBalance * strategyConfig.positions.balanceUsageRatio;
  1435. // 基础仓位
  1436. const basePositionValue = Math.max(
  1437. availableBalance * strategyConfig.positions.basePositionRatio,
  1438. minOrderValue * 1.05
  1439. );
  1440. const basePositionSize = basePositionValue / currentPrice;
  1441. const adjustedBaseSize = Math.ceil(basePositionSize / lotSize) * lotSize;
  1442. // 刷量仓位
  1443. const volumePositionValue = Math.max(
  1444. availableBalance * strategyConfig.positions.volumePositionRatio,
  1445. minOrderValue
  1446. );
  1447. const volumePositionSize = volumePositionValue / currentPrice;
  1448. const adjustedVolumeSize = Math.ceil(volumePositionSize / lotSize) * lotSize;
  1449. console.log(`可用余额: ${availableBalance.toFixed(2)} USDC (${(strategyConfig.positions.balanceUsageRatio * 100).toFixed(0)}%)`);
  1450. console.log(`基础仓位: ${adjustedBaseSize.toFixed(8)} BTC (${(adjustedBaseSize * currentPrice).toFixed(2)} USDC)`);
  1451. console.log(`刷量仓位: ${adjustedVolumeSize.toFixed(8)} BTC (${(adjustedVolumeSize * currentPrice).toFixed(2)} USDC)`);
  1452. // 5. 构建策略配置(从配置文件)
  1453. console.log('\n⚙️ 构建策略配置...');
  1454. const configManager = new DeltaNeutralConfigManager();
  1455. const simpleConfig: DeltaNeutralConfig = {
  1456. // 基础仓位配置
  1457. basePositionRatio: strategyConfig.positions.basePositionRatio,
  1458. basePositionSize: adjustedBaseSize,
  1459. // 刷量仓位配置
  1460. volumePositionRatio: strategyConfig.positions.volumePositionRatio,
  1461. maxVolumePositionSize: adjustedVolumeSize,
  1462. // Delta中性配置
  1463. maxDeltaDeviation: strategyConfig.deltaRebalancing.maxDeltaDeviation,
  1464. rebalanceThreshold: strategyConfig.deltaRebalancing.rebalanceThreshold,
  1465. // 交易配置 - 限价单优先(降低手续费)
  1466. preferredOrderType: strategyConfig.orderStrategy.preferredOrderType as 'limit' | 'market',
  1467. limitOrderSpread: strategyConfig.orderStrategy.limitOrderSpread,
  1468. emergencyMarketThreshold: strategyConfig.orderStrategy.emergencyMarketThreshold,
  1469. // 风险控制
  1470. maxDrawdown: strategyConfig.risk.maxDrawdown,
  1471. maxPositionSize: adjustedBaseSize * strategyConfig.risk.positionSizeMultiplier,
  1472. stopLossThreshold: strategyConfig.risk.stopLossThreshold
  1473. };
  1474. configManager.updateConfig(simpleConfig);
  1475. console.log('✅ 策略配置完成');
  1476. console.log(`订单类型: ${simpleConfig.preferredOrderType}单优先`);
  1477. console.log(`价差: ${(simpleConfig.limitOrderSpread * 100).toFixed(3)}%`);
  1478. console.log(`Delta偏差限制: ${(simpleConfig.maxDeltaDeviation * 100).toFixed(1)}%`);
  1479. console.log(`最大回撤: ${(simpleConfig.maxDrawdown * 100).toFixed(1)}%`);
  1480. // 6. 创建账户对象
  1481. const accounts: Account[] = accountsConfig.map((acc: any) => new Account({
  1482. id: acc.id,
  1483. name: acc.name,
  1484. privateKey: acc.privateKey,
  1485. apiKey: acc.apiKey || 'not_required',
  1486. address: acc.address,
  1487. isActive: acc.isActive !== false,
  1488. balance: {
  1489. total: accountBalance,
  1490. available: availableBalance,
  1491. used: 0
  1492. },
  1493. positions: []
  1494. }));
  1495. // 7. 创建简洁版策略实例
  1496. console.log('\n🎯 创建简洁版策略实例...');
  1497. const strategy = new SimpleDeltaNeutralStrategy(
  1498. simpleConfig,
  1499. pacificaClient,
  1500. accounts
  1501. );
  1502. console.log('✅ 简洁版策略创建成功');
  1503. // 8. 清理历史订单(策略启动前)
  1504. console.log('\n🧹 清理历史开放订单...');
  1505. try {
  1506. const cleanupService = new OrderCleanupService();
  1507. // 为每个账户初始化清理服务
  1508. for (const account of accounts) {
  1509. cleanupService.initializeAccount(account);
  1510. }
  1511. // 清理选项:清理所有非 reduce_only 订单
  1512. const cleanupOptions: CleanupOptions = {
  1513. cleanAll: true,
  1514. includeReduceOnly: false, // 保留保护性订单
  1515. mode: 'selective',
  1516. dryRun: false
  1517. };
  1518. console.log('正在从 Pacifica API 获取开放订单...');
  1519. const results = await cleanupService.cleanupMultipleAccounts(
  1520. accounts,
  1521. cleanupOptions
  1522. );
  1523. // 汇总清理结果
  1524. let totalOrders = 0;
  1525. let totalCancelled = 0;
  1526. let totalFailed = 0;
  1527. for (const [accountId, result] of results.entries()) {
  1528. totalOrders += result.totalOrders;
  1529. totalCancelled += result.cancelledOrders;
  1530. totalFailed += result.failedOrders;
  1531. if (result.totalOrders > 0) {
  1532. console.log(` 账户 ${accountId.slice(0, 8)}: ${result.totalOrders} 个订单, 已取消 ${result.cancelledOrders}, 失败 ${result.failedOrders}`);
  1533. }
  1534. }
  1535. if (totalOrders > 0) {
  1536. console.log(`✅ 历史订单清理完成: ${totalCancelled}/${totalOrders} 个订单已取消`);
  1537. if (totalFailed > 0) {
  1538. console.log(`⚠️ ${totalFailed} 个订单取消失败`);
  1539. }
  1540. } else {
  1541. console.log('✅ 没有历史开放订单需要清理');
  1542. }
  1543. await cleanupService.shutdown();
  1544. } catch (error) {
  1545. console.log('⚠️ 历史订单清理失败,继续启动策略');
  1546. console.log(`错误: ${error instanceof Error ? error.message : '未知错误'}`);
  1547. }
  1548. // 9. 显示策略信息
  1549. console.log('\n📋 简洁版策略特点:');
  1550. console.log('• 超保守参数 - 2%基础仓位 + 5%刷量仓位');
  1551. console.log('• 严格风险控制 - 1%最大回撤,0.1%Delta偏差');
  1552. console.log('• 智能重试机制 - 自动重试失败的API调用');
  1553. console.log('• 智能错误恢复 - 连续错误自动暂停和恢复');
  1554. console.log('• 健康检查系统 - 5分钟间隔健康监控');
  1555. console.log('• 统计信息持久化 - 10分钟间隔保存统计');
  1556. console.log('• 完整的生命周期管理 - 订单自动跟踪和清理');
  1557. console.log('• 自动订单清理 - 启动前/停止后自动清理');
  1558. console.log('• API频率控制 - 2秒间隔,避免限制');
  1559. console.log('• 简洁日志输出 - 只显示关键信息');
  1560. console.log('\n🔄 开始执行简洁版策略...');
  1561. // 9. 初始化策略
  1562. await strategy.initialize();
  1563. console.log('✅ 策略初始化完成');
  1564. // 10. 启动策略
  1565. console.log('\n📊 简洁版策略已启动,开始简洁运行...');
  1566. console.log('按 Ctrl+C 停止策略');
  1567. // 11. 优雅关闭处理
  1568. process.on('SIGINT', async () => {
  1569. console.log('\n🛑 收到停止信号,正在优雅关闭策略...');
  1570. try {
  1571. await strategy.stop();
  1572. console.log('✅ 策略已安全停止');
  1573. process.exit(0);
  1574. } catch (error) {
  1575. console.error('❌ 停止策略时发生错误:', error);
  1576. process.exit(1);
  1577. }
  1578. });
  1579. // 12. 错误处理
  1580. process.on('uncaughtException', async (error) => {
  1581. console.error('❌ 未捕获的异常:', error);
  1582. try {
  1583. await strategy.stop();
  1584. } catch (stopError) {
  1585. console.error('❌ 停止策略时发生错误:', stopError);
  1586. }
  1587. process.exit(1);
  1588. });
  1589. process.on('unhandledRejection', async (reason) => {
  1590. console.error('❌ 未处理的Promise拒绝:', reason);
  1591. try {
  1592. await strategy.stop();
  1593. } catch (stopError) {
  1594. console.error('❌ 停止策略时发生错误:', stopError);
  1595. }
  1596. process.exit(1);
  1597. });
  1598. console.log('\n🎉 简洁版Delta中性刷量策略已启动!');
  1599. console.log('策略将持续简洁运行,自动处理API错误和网络问题...');
  1600. } catch (error) {
  1601. console.error('❌ 策略启动失败:', error);
  1602. process.exit(1);
  1603. }
  1604. }
  1605. // 运行策略
  1606. runSimpleDeltaNeutralStrategy().catch(console.error);