交割合约现货套利策略测试版


创建日期: 2025-11-28 16:20:48 最后修改: 2025-12-12 11:42:22
复制: 0 点击次数: 10
avatar of ianzeng123 ianzeng123
2
关注
327
关注者
策略源码
// 仅做学术研究使用,请勿直接用于实盘

// ==================== 全局配置 ====================
const CONFIG = {
    // === 平稳性检测参数 ===
    adfWindow: 1000,
    adfPValueThreshold: 0.1,
    stationarityCheckInterval: 3600000,
    consecutiveFailThreshold: 3,
    
    // === 入场/出场信号参数 ===
    zScoreEntry: 1.0,
    zScoreExitTarget: 0.5,
    zScoreMaxDeviation: 0.5,
    
    // === 风控参数 ===
    stopLossRate: 0.015,  // 只保留止损,去掉止盈
    maxHoldDays: 10,
    
    // === 限价单参数 ===
    limitOrderSpreadRatio: 0.3,
    orderWaitTimeout: 45000,
    orderCheckInterval: 1000,
    
    // === 冷却期参数 ===
    cooldownDuration: 600000,  // 10分钟
    opportunityLostCooldown: 60000,  // 1分钟
    
    // === 平仓验证参数 ===
    spreadTolerance: 30,
    slippageWarning: 50,
    closeOrderTimeout: 15000,
    
    // === 目标区间动态调整参数 ===
    minProfitSpaceRate: 0.005,
    minProfitSpaceUSDT: 50,
    useFixedProfitSpace: false,
    
    // === 余额检查参数 ===
    minUSDTReserve: 10,  // 最低保留USDT
    balanceCheckRetries: 3,  // 余额检查重试次数
    
    // === 回滚参数 (v5.1新增) ===
    maxRollbackRetries: 3,  // 回滚最大重试次数
    
    // === 原有参数 ===
    checkInterval: 1000,
    orderAmount: 0.05,
    minDaysToDelivery: 7,
    marginLevel: 10,
    
    // === 数据管理参数 ===
    maxHistoryLength: 5000,
    minHistoryForTest: 200,
    
    // === 合约筛选 ===
    allowedCoins: ['BTC'],
};

// ==================== 全局数据存储 ====================
let contractPairs = [];
let priceHistory = {};
let positionRecords = {};
let closedTrades = [];
let stationarityCache = {};
let stationarityFailCount = {};
let lastStationarityCheck = {};
let nextStationarityCheckTime = 0;
let strategyStartTime = 0;
let pairCooldowns = {};
let opportunityLostCooldowns = {};
let accumulatedProfit = 0;

// ==================== 工具函数(数学计算)====================
function mean(arr) {
    const s = arr.reduce((a,b)=>a+b,0);
    return s/arr.length;
}

function variance(arr) {
    const m = mean(arr);
    return arr.reduce((s,x)=>s + (x-m)*(x-m), 0) / (arr.length-1);
}

function dot(a,b){
    let s=0; for(let i=0;i<a.length;i++) s+=a[i]*b[i]; return s;
}

function ols(X, Y) {
    const n = Y.length;
    const k = X[0].length;
    const XtX = Array.from({length:k}, ()=>Array(k).fill(0));
    const XtY = Array(k).fill(0);
    for(let i=0;i<n;i++){
        for(let j=0;j<k;j++){
            XtY[j] += X[i][j] * Y[i];
            for(let l=0;l<k;l++) XtX[j][l] += X[i][j]*X[i][l];
        }
    }
    
    function invertMatrix(A){
        const m = A.length;
        const B = A.map(row=>row.slice());
        const I = Array.from({length:m}, (_,i)=>Array.from({length:m}, (__,j)=> i===j?1:0));
        for(let i=0;i<m;i++){
            let piv = i;
            for(let r=i;r<m;r++) if(Math.abs(B[r][i])>Math.abs(B[piv][i])) piv=r;
            if(Math.abs(B[piv][i])<1e-12) throw new Error('Singular matrix');
            [B[i], B[piv]] = [B[piv], B[i]];
            [I[i], I[piv]] = [I[piv], I[i]];
            const div = B[i][i];
            for(let c=0;c<m;c++){ B[i][c] /= div; I[i][c] /= div; }
            for(let r=0;r<m;r++) if(r!==i){
                const f = B[r][i];
                for(let c=0;c<m;c++){ B[r][c] -= f*B[i][c]; I[r][c] -= f*I[i][c]; }
            }
        }
        return I;
    }
    
    const XtXinv = invertMatrix(XtX);
    const beta = Array(k).fill(0);
    for(let j=0;j<k;j++) for(let l=0;l<k;l++) beta[j] += XtXinv[j][l]*XtY[l];
    
    const res = Array(n).fill(0);
    for(let i=0;i<n;i++){
        let pred=0; for(let j=0;j<k;j++) pred += X[i][j]*beta[j];
        res[i] = Y[i]-pred;
    }
    const rss = res.reduce((s,r)=>s+r*r,0);
    const sigma2 = rss / (n - k);
    const cov = XtXinv.map(row=>row.map(v=>v*sigma2));
    return {beta, cov, sigma2, res};
}

function tStat(beta, cov, idx){
    const se = Math.sqrt(Math.max(1e-16, cov[idx][idx]));
    return beta[idx]/se;
}

function normalCdf(x){
    return 0.5*(1 + erf(x/Math.sqrt(2)));
}

function erf(x){
    const sign = x<0?-1:1; x = Math.abs(x);
    const a1=  0.254829592;
    const a2= -0.284496736;
    const a3=  1.421413741;
    const a4= -1.453152027;
    const a5=  1.061405429;
    const p=  0.3275911;
    const t = 1.0/(1.0 + p*x);
    const y = 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*Math.exp(-x*x);
    return sign*y;
}

function tPValue(t, df){
    const z = Math.abs(t);
    return 2*(1 - normalCdf(z));
}

function adfTest(series, maxLag=null){
    const n = series.length;
    if(n<10) throw new Error('series too short');
    if(maxLag===null) maxLag = Math.floor(12*Math.pow(n/100, 1/4));
    
    const dX = Array(n-1).fill(0);
    for(let i=1;i<n;i++) dX[i-1] = series[i]-series[i-1];
    
    const p = maxLag;
    const rows = [];
    const Ys = [];
    for(let t=p+1; t<n; t++){
        const row = [];
        row.push(1);
        row.push(series[t-1]);
        for(let j=1;j<=p;j++) row.push( dX[t-1-j] );
        rows.push(row);
        Ys.push(dX[t-1]);
    }
    if(rows.length <= rows[0].length) throw new Error('not enough observations');
    
    const res = ols(rows, Ys);
    const tstat = tStat(res.beta, res.cov, 1);
    const df = Ys.length - res.beta.length;
    const pval = tPValue(tstat, df);
    return { tStat: tstat, pValue: pval, usedLag: p };
}

function parseDeliveryDateFromString(dateStr) {
    if (!dateStr || dateStr.length !== 6) return null;
    let year = parseInt('20' + dateStr.substring(0, 2));
    let month = parseInt(dateStr.substring(2, 4)) - 1;
    let day = parseInt(dateStr.substring(4, 6));
    let date = new Date(Date.UTC(year, month, day, 16, 0, 0, 0));
    return date.getTime();
}

// ==================== 数据层 (DataLayer) ====================
const DataLayer = {
    /**
     * 获取盘口中间价(带重试机制)
     */
    getDepthMidPrice: function(exchange, symbol, logDetail = false, maxRetries = 3) {
        for (let attempt = 1; attempt <= maxRetries; attempt++) {
            try {
                let depth = exchange.GetDepth(symbol);
                if (!depth || !depth.Bids || depth.Bids.length === 0 || !depth.Asks || depth.Asks.length === 0) {
                    if (attempt < maxRetries) {
                        Log(`⚠️ 获取${symbol}盘口失败,第${attempt}次重试...`);
                        Sleep(100);
                        continue;
                    }
                    Log(`❌ 获取${symbol}盘口失败(已重试${maxRetries}次),无法继续`);
                    return null;
                }
                
                let bestBid = depth.Bids[0].Price;
                let bestAsk = depth.Asks[0].Price;
                let midPrice = (bestBid + bestAsk) / 2;
                
                if (logDetail) {
                    let spread = bestAsk - bestBid;
                    let spreadRate = spread / midPrice * 100;
                    Log(`📊 ${symbol} 盘口: Bid=${bestBid.toFixed(2)}, Ask=${bestAsk.toFixed(2)}, Mid=${midPrice.toFixed(2)}, Spread=${spread.toFixed(2)} (${spreadRate.toFixed(3)}%)`);
                }
                
                return midPrice;
            } catch(e) {
                if (attempt < maxRetries) {
                    Log(`⚠️ 获取${symbol}盘口异常(第${attempt}次): ${e.message},正在重试...`);
                    Sleep(500);
                    continue;
                }
                Log(`❌ 获取${symbol}盘口异常(已重试${maxRetries}次): ${e.message}`);
                return null;
            }
        }
        return null;
    },

    /**
     * 初始化合约配对
     */
    initContractPairs: function() {
        // 预热GetTicker
        exchanges[0].GetTicker('BTC_USDT');
        exchanges[0].GetTicker('ETH_USDT');
        exchanges[1].GetTicker('BTC_USDT.quarter');
        exchanges[1].GetTicker('BTC_USDT.next_quarter');
        
        let spotMarkets = exchanges[0].GetMarkets();
        let futureMarkets = exchanges[1].GetMarkets();
        
        if (!spotMarkets || !futureMarkets) {
            Log('获取市场信息失败');
            return false;
        }
        
        Log('现货市场总数:', Object.keys(spotMarkets).length);
        Log('交割合约市场总数:', Object.keys(futureMarkets).length);
        
        let spotContracts = [];
        let deliveryContracts = [];
        
        for (let key in spotMarkets) {
            let market = spotMarkets[key];
            let lowerKey = key.toLowerCase();
            if (lowerKey.endsWith('_usdt')) {
                spotContracts.push({ key: key, market: market });
            }
        }
        
        for (let key in futureMarkets) {
            let market = futureMarkets[key];
            let lowerKey = key.toLowerCase();
            if (lowerKey.includes('_usdt.') && !lowerKey.endsWith('.swap')) {
                deliveryContracts.push({ key: key, market: market });
            }
        }
        
        Log('找到现货合约数量:', spotContracts.length);
        Log('找到交割合约数量:', deliveryContracts.length);
        
        contractPairs = [];
        
        for (let delivery of deliveryContracts) {
            let lowerKey = delivery.key.toLowerCase();
            let coinName = lowerKey.split('_usdt.')[0];
            
            if (CONFIG.allowedCoins.length > 0 && 
                !CONFIG.allowedCoins.includes(coinName.toUpperCase())) {
                continue;
            }
            
            let spotKey = coinName + '_usdt';
            let matchedSpot = spotContracts.find(s => s.key.toLowerCase() === spotKey);
            
            if (matchedSpot) {
                let deliveryDateStr = null;
                let deliveryDate = null;
                
                if (delivery.market.Symbol) {
                    let symbol = delivery.market.Symbol;
                    let match = symbol.match(/(\d{6})$/);
                    if (match) {
                        deliveryDateStr = match[1];
                        deliveryDate = parseDeliveryDateFromString(deliveryDateStr);
                    }
                }
                
                if (!deliveryDate) {
                    Log('⚠️ 无法解析交割日期,跳过:', delivery.key);
                    continue;
                }
                
                let daysToDelivery = (deliveryDate - Date.now()) / (1000 * 60 * 60 * 24);
                
                if (daysToDelivery < CONFIG.minDaysToDelivery) {
                    Log(`⚠️ ${coinName.toUpperCase()} 交割日太近(${daysToDelivery.toFixed(1)}天),跳过`);
                    continue;
                }
                
                let deliveryType = lowerKey.split('_usdt.')[1];
                let deliveryTypeMap = {
                    'this_week': '本周交割',
                    'next_week': '次周交割',
                    'quarter': '当季交割',
                    'next_quarter': '次季交割',
                    'bi_quarter': '双季交割',
                    'month': '本月交割',
                    'next_month': '下月交割'
                };
                let deliveryTypeName = deliveryTypeMap[deliveryType] || deliveryType.toUpperCase();
                let ctVal = delivery.market.CtVal || 1;
                
                contractPairs.push({
                    coin: coinName.toUpperCase(),
                    spotSymbol: matchedSpot.key,
                    deliverySymbol: delivery.key,
                    deliveryType: deliveryType,
                    deliveryTypeName: deliveryTypeName,
                    deliveryDateStr: deliveryDateStr,
                    deliveryDate: deliveryDate,
                    daysToDelivery: daysToDelivery,
                    ctVal: ctVal,
                    spotPrice: 0,
                    deliveryPrice: 0,
                    spread: 0,
                    spreadRate: 0
                });
                
                priceHistory[delivery.key] = [];
                stationarityFailCount[delivery.key] = 0;
                
                Log('✅ 配对成功:', coinName.toUpperCase(), 
                    matchedSpot.key, '<->', delivery.key,
                    '| 交割日期:', deliveryDateStr,
                    '| 剩余天数:', daysToDelivery.toFixed(1),
                    '| 合约价值(CtVal):', ctVal);
            }
        }
        
        Log('成功配对合约数量:', contractPairs.length);
        Log('允许交易币种:', CONFIG.allowedCoins.join(', '));
        return contractPairs.length > 0;
    },

    /**
     * 更新所有合约价格和历史数据
     */
    updatePrices: function() {
        for (let pair of contractPairs) {
            let spotTicker = exchanges[0].GetTicker(pair.spotSymbol);
            if (!spotTicker || spotTicker.length === 0) return false;
            
            let deliveryTicker = exchanges[1].GetTicker(pair.deliverySymbol);
            if (!deliveryTicker || deliveryTicker.length === 0) return false;
            
            pair.spotPrice = spotTicker.Last;
            pair.deliveryPrice = deliveryTicker.Last;
            pair.spread = pair.deliveryPrice - pair.spotPrice;
            pair.spreadRate = pair.spread / pair.spotPrice;
            pair.daysToDelivery = (pair.deliveryDate - Date.now()) / (1000 * 60 * 60 * 24);
            
            try {
                if (!priceHistory[pair.deliverySymbol]) {
                    priceHistory[pair.deliverySymbol] = [];
                }
                
                let existingHistory = priceHistory[pair.deliverySymbol];
                
                if (existingHistory.length === 0) {
                    let spotRecords = exchanges[0].GetRecords(pair.spotSymbol, PERIOD_M1, 2000);
                    if (!spotRecords || spotRecords.length === 0) {
                        Log(`⚠️ 获取 ${pair.spotSymbol} 历史K线失败`);
                        continue;
                    }

                    Sleep(1000);
                    let deliveryRecords = exchanges[1].GetRecords(pair.deliverySymbol, PERIOD_M1, 2000);
                    if (!deliveryRecords || deliveryRecords.length === 0) {
                        Log(`⚠️ 获取 ${pair.deliverySymbol} 历史K线失败`);
                        continue;
                    } else {
                        Log(`✅ ${pair.deliverySymbol} 加载了 ${deliveryRecords.length} 根历史K线`);
                    }

                    let minLength = Math.min(spotRecords.length, deliveryRecords.length);
                    let spreadHistory = [];
                    for (let i = 0; i < minLength; i++) {
                        let spotClose = spotRecords[i].Close;
                        let deliveryClose = deliveryRecords[i].Close;
                        let klineTime = spotRecords[i].Time;
                        let spread = deliveryClose - spotClose;
                        let spreadRate = spread / spotClose;
                        
                        spreadHistory.push({
                            time: klineTime,
                            spreadRate: spreadRate,
                            spread: spread,
                            spotPrice: spotClose,
                            deliveryPrice: deliveryClose
                        });
                    }
                    priceHistory[pair.deliverySymbol] = spreadHistory;
                    
                } else {
                    let spotRecords = exchanges[0].GetRecords(pair.spotSymbol, PERIOD_M1, 10);
                    if (!spotRecords || spotRecords.length === 0) continue;
                    
                    let deliveryRecords = exchanges[1].GetRecords(pair.deliverySymbol, PERIOD_M1, 10);
                    if (!deliveryRecords || deliveryRecords.length === 0) continue;
                    
                    let minLength = Math.min(spotRecords.length, deliveryRecords.length);
                    let lastHistoryTime = existingHistory[existingHistory.length - 1].time;
                    
                    for (let i = 0; i < minLength; i++) {
                        let klineTime = spotRecords[i].Time;
                        if (klineTime > lastHistoryTime) {
                            let spotClose = spotRecords[i].Close;
                            let deliveryClose = deliveryRecords[i].Close;
                            let spread = deliveryClose - spotClose;
                            let spreadRate = spread / spotClose;
                            
                            existingHistory.push({
                                time: klineTime,
                                spreadRate: spreadRate,
                                spread: spread,
                                spotPrice: spotClose,
                                deliveryPrice: deliveryClose
                            });
                        }
                    }
                    
                    if (existingHistory.length > CONFIG.maxHistoryLength) {
                        let excess = existingHistory.length - CONFIG.maxHistoryLength;
                        existingHistory.splice(0, excess);
                    }
                }
            } catch (e) {
                Log(`❌ 处理 ${pair.deliverySymbol} 历史数据异常:`, e.message);
            }
        }
        return true;
    },

    /**
     * 持久化保存历史数据
     */
    saveHistoryData: function() {
        let compactHistory = {};
        for (let symbol in priceHistory) {
            let history = priceHistory[symbol];
            compactHistory[symbol] = history.slice(-2000);
        }
        _G('priceHistory', compactHistory);
        _G('stationarityFailCount', stationarityFailCount);
        _G('pairCooldowns', pairCooldowns);
        _G('opportunityLostCooldowns', opportunityLostCooldowns);
    },

    /**
     * 加载持久化数据
     */
    loadHistoryData: function() {
        try {
            let savedHistory = _G('priceHistory');
            if (savedHistory) {
                priceHistory = savedHistory;
                Log('📥 已恢复历史数据');
            }
            
            let savedFailCount = _G('stationarityFailCount');
            if (savedFailCount) {
                stationarityFailCount = savedFailCount;
                Log('📥 已恢复平稳性计数');
            }
            
            let savedClosedTrades = _G('closedTrades');
            if (savedClosedTrades) {
                closedTrades = savedClosedTrades;
                Log('📥 已恢复历史交易记录:', closedTrades.length, '笔');
            }
            
            let savedCooldowns = _G('pairCooldowns');
            if (savedCooldowns) {
                pairCooldowns = savedCooldowns;
                let now = Date.now();
                let activeCooldowns = 0;
                for (let symbol in pairCooldowns) {
                    if (pairCooldowns[symbol] > now) activeCooldowns++;
                }
                Log('📥 已恢复10分钟冷却期数据:', activeCooldowns, '个交易对处于冷却中');
            }
            
            let savedOpportunityCooldowns = _G('opportunityLostCooldowns');
            if (savedOpportunityCooldowns) {
                opportunityLostCooldowns = savedOpportunityCooldowns;
                let now = Date.now();
                let activeOpportunityCooldowns = 0;
                for (let symbol in opportunityLostCooldowns) {
                    if (opportunityLostCooldowns[symbol] > now) activeOpportunityCooldowns++;
                }
                Log('📥 已恢复套利机会消失冷却数据:', activeOpportunityCooldowns, '个交易对处于1分钟冷却中');
            }
            
            return true;
        } catch(e) {
            Log('⚠️ 加载历史数据失败:', e.message);
        }
        return false;
    },

    /**
     * 初始化账户记录
     */
    initializeAccountRecords: function() {
        exchanges[0].SetCurrency(contractPairs[0].spotSymbol);
        let spotAccount = exchanges[0].GetAccount();
        let futureAccount = exchanges[1].GetAccount();
        
        if (!spotAccount || !futureAccount) {
            Log('❌ 获取初始账户信息失败');
            return false;
        }
        
        let savedProfit = _G('accumulatedProfit');
        if (savedProfit !== null && savedProfit !== undefined) {
            accumulatedProfit = savedProfit;
            Log('📥 恢复累计盈亏:', accumulatedProfit.toFixed(4), 'USDT');
        }
        
        Log('💰 策略账户信息:');
        Log('  现货USDT余额:', spotAccount.Balance.toFixed(4));
        Log('  期货权益:', futureAccount.Equity.toFixed(4));
        Log('  累计盈亏:', accumulatedProfit.toFixed(4), 'USDT');
        
        return true;
    }
};

// ==================== 信号层 (SignalLayer) ====================
const SignalLayer = {
    /**
     * ADF平稳性检验
     */
    evaluateSpreadStationarity: function(deliverySymbol) {
        let history = priceHistory[deliverySymbol];
        
        if (!history || history.length < CONFIG.minHistoryForTest) {
            return {
                isStationary: false,
                canTrade: false,
                reason: `数据不足(${history ? history.length : 0}/${CONFIG.minHistoryForTest})`,
                dataLength: history ? history.length : 0,
                consecutiveFails: stationarityFailCount[deliverySymbol] || 0,
                timestamp: Date.now()
            };
        }
        
        let now = Date.now();
        if (stationarityCache[deliverySymbol]) {
            let lastCheck = lastStationarityCheck[deliverySymbol] || 0;
            if (now - lastCheck < CONFIG.stationarityCheckInterval) {
                return stationarityCache[deliverySymbol];
            }
        }
        
        let spreadRates = history.map(h => h.spreadRate);
        let adfRes = null;
        let adfPass = false;
        
        try {
            let testWindow = Math.min(CONFIG.adfWindow, spreadRates.length);
            let testSeries = spreadRates.slice(-testWindow);
            adfRes = adfTest(testSeries);
            adfPass = adfRes.pValue < CONFIG.adfPValueThreshold;
        } catch(e) {
            Log(`❌ ${deliverySymbol} ADF检验异常:`, e.message);
            return {
                isStationary: false,
                canTrade: false,
                reason: 'ADF检验失败',
                dataLength: spreadRates.length,
                consecutiveFails: stationarityFailCount[deliverySymbol] || 0,
                timestamp: now
            };
        }
        
        if (!adfPass) {
            stationarityFailCount[deliverySymbol] = (stationarityFailCount[deliverySymbol] || 0) + 1;
        } else {
            stationarityFailCount[deliverySymbol] = 0;
        }
        
        let consecutiveFails = stationarityFailCount[deliverySymbol];
        let canTrade = consecutiveFails < CONFIG.consecutiveFailThreshold;
        
        let finalReason = '';
        if (adfPass && canTrade) {
            finalReason = '✅ 平稳,可交易';
        } else if (adfPass && !canTrade) {
            finalReason = `⚠️ 当前平稳,但之前连续${consecutiveFails}次不平稳`;
        } else if (!adfPass && canTrade) {
            finalReason = `⚠️ 当前不平稳(${consecutiveFails}/${CONFIG.consecutiveFailThreshold}),仍可交易`;
        } else {
            finalReason = `❌ 禁止交易 - 连续${consecutiveFails}次不平稳`;
        }
        
        let result = {
            isStationary: adfPass,
            canTrade: canTrade,
            reason: finalReason,
            dataLength: spreadRates.length,
            adf: adfRes,
            consecutiveFails: consecutiveFails,
            timestamp: now
        };
        
        stationarityCache[deliverySymbol] = result;
        lastStationarityCheck[deliverySymbol] = now;
        
        return result;
    },

    /**
     * 定时触发平稳性检验
     */
    runStationarityChecks: function() {
        let now = Date.now();
        if (now < nextStationarityCheckTime) return;
        
        for (let pair of contractPairs) {
            if (pair.daysToDelivery < CONFIG.minDaysToDelivery) continue;
            SignalLayer.evaluateSpreadStationarity(pair.deliverySymbol);
        }
        
        nextStationarityCheckTime = now + CONFIG.stationarityCheckInterval;
        let nextCheckDate = new Date(nextStationarityCheckTime);
        Log('⏰ 平稳性下次检验时间:', nextCheckDate.toLocaleString());
    },

    /**
     * 计算Z-Score
     */
    calculateZScore: function(deliverySymbol) {
        let history = priceHistory[deliverySymbol];
        if (!history || history.length < CONFIG.minHistoryForTest) return null;
        
        let spreadRates = history.map(h => h.spreadRate);
        let mu = mean(spreadRates);
        let sigma = Math.sqrt(variance(spreadRates));
        let currentSpreadRate = history[history.length - 1].spreadRate;
        let z = (currentSpreadRate - mu) / (sigma || 1e-6);
        
        return {
            zScore: z,
            mean: mu,
            std: sigma,
            current: currentSpreadRate,
            dataLength: spreadRates.length
        };
    },

    /**
     * 判断价格偏离方向
     */
    detectPriceDeviation: function(pair, zInfo) {
        let history = priceHistory[pair.deliverySymbol];
        if (!history || history.length < 100) {
            return {
                isSpotDeviation: false,
                isDeliveryDeviation: false,
                reason: '数据不足,无法判断偏离方向',
                spotDeviationRate: 0,
                deliveryDeviationRate: 0
            };
        }
        
        let spotPrices = history.slice(-100).map(h => h.spotPrice);
        let deliveryPrices = history.slice(-100).map(h => h.deliveryPrice);
        let spotMean = mean(spotPrices);
        let deliveryMean = mean(deliveryPrices);
        let spotDeviationRate = Math.abs((pair.spotPrice - spotMean) / spotMean);
        let deliveryDeviationRate = Math.abs((pair.deliveryPrice - deliveryMean) / deliveryMean);
        
        Log(`📊 偏离分析: 现货偏离=${(spotDeviationRate*100).toFixed(3)}%, 期货偏离=${(deliveryDeviationRate*100).toFixed(3)}%`);
        
        if (spotDeviationRate > deliveryDeviationRate) {
            return {
                isSpotDeviation: true,
                isDeliveryDeviation: false,
                reason: `现货偏离更大(${(spotDeviationRate*100).toFixed(3)}% > ${(deliveryDeviationRate*100).toFixed(3)}%)`,
                spotDeviationRate: spotDeviationRate,
                deliveryDeviationRate: deliveryDeviationRate
            };
        } else if (deliveryDeviationRate > spotDeviationRate) {
            return {
                isSpotDeviation: false,
                isDeliveryDeviation: true,
                reason: `期货偏离更大(${(deliveryDeviationRate*100).toFixed(3)}% > ${(spotDeviationRate*100).toFixed(3)}%)`,
                spotDeviationRate: spotDeviationRate,
                deliveryDeviationRate: deliveryDeviationRate
            };
        } else {
            return {
                isSpotDeviation: false,
                isDeliveryDeviation: false,
                reason: '双方偏离相同或偏离不明显',
                spotDeviationRate: spotDeviationRate,
                deliveryDeviationRate: deliveryDeviationRate
            };
        }
    },

    /**
     * 判断是否开仓
     */
    shouldOpenPosition: function(pair) {
        let stationarity = stationarityCache[pair.deliverySymbol];
        
        if (!stationarity || !stationarity.canTrade) {
            return {
                should: false,
                reason: stationarity ? ('不可交易: ' + stationarity.reason) : '等待平稳性检验',
                detail: stationarity
            };
        }
        
        let zInfo = SignalLayer.calculateZScore(pair.deliverySymbol);
        if (!zInfo) {
            return {
                should: false,
                reason: '无法计算Z-Score',
                detail: null
            };
        }
        
        let absZ = Math.abs(zInfo.zScore);
        if (absZ < CONFIG.zScoreEntry) {
            return {
                should: false,
                reason: `Z-Score未偏离(|z|=${absZ.toFixed(2)} < ${CONFIG.zScoreEntry})`,
                detail: zInfo
            };
        }
        
        let direction = zInfo.zScore > 0 ? 'positive' : 'negative';
        let deviation = SignalLayer.detectPriceDeviation(pair, zInfo);
        
        let priceSnapshot = {
            spotPrice: pair.spotPrice,
            deliveryPrice: pair.deliveryPrice,
            spread: pair.spread,
            spreadRate: pair.spreadRate
        };
        
        let mean = zInfo.mean;
        let std = zInfo.std;
        let targetSpreadRateUpper = mean + CONFIG.zScoreExitTarget * std;
        let targetSpreadRateLower = mean - CONFIG.zScoreExitTarget * std;
        let targetSpreadUpper = targetSpreadRateUpper * pair.spotPrice;
        let targetSpreadLower = targetSpreadRateLower * pair.spotPrice;
        
        let maxDeviationZ = absZ * (1 + CONFIG.zScoreMaxDeviation);
        let maxDeviationSpreadRate = mean + (zInfo.zScore > 0 ? 1 : -1) * maxDeviationZ * std;
        let maxDeviationSpread = maxDeviationSpreadRate * pair.spotPrice;
        
        let history = priceHistory[pair.deliverySymbol];
        let spreads = history.slice(-100).map(h => h.spread);
        let spreadSum = spreads.reduce((a, b) => a + b, 0);
        let avgSpread = spreadSum / spreads.length;
        
        return {
            should: true,
            reason: `✅ Z-Score偏离正常区间 z=${zInfo.zScore.toFixed(2)}`,
            direction: direction,
            deviation: deviation,
            priceSnapshot: priceSnapshot,
            openZScore: zInfo.zScore,
            openMean: mean,
            openStd: std,
            targetSpreadUpper: targetSpreadUpper,
            targetSpreadLower: targetSpreadLower,
            maxDeviationSpread: maxDeviationSpread,
            avgSpread: avgSpread,
            detail: {
                stationarity: stationarity,
                zInfo: zInfo
            }
        };
    },

    /**
     * 判断是否平仓(去掉止盈,只保留止损)
     */
    shouldClosePosition: function(deliverySymbol, currentPair) {
        let record = positionRecords[deliverySymbol];
        if (!record) return { should: false };
        
        let deliveryPos = ExecutionLayer.getPositionBySymbol(deliverySymbol);
        if (!deliveryPos) return { should: false };
        
        let pnl = SignalLayer.calculateUnrealizedPnL(record, currentPair);
        if (!pnl) return { should: false };
        
        let currentSpread = pnl.currentDeliveryPrice - pnl.currentSpotPrice;
        
        // 价差回归判断
        if (currentSpread >= record.targetSpreadLower && 
            currentSpread <= record.targetSpreadUpper) {
            return {
                should: true,
                reason: '✅ 价差回归目标区间',
                detail: `判断时Depth价差=${currentSpread.toFixed(2)} ∈ [${record.targetSpreadLower.toFixed(2)}, ${record.targetSpreadUpper.toFixed(2)}] | ` +
                        `实时盈亏: ${(pnl.totalPnlRate*100).toFixed(4)}%`,
                priceSnapshot: {
                    snapshotSpotPrice: pnl.currentSpotPrice,
                    snapshotDeliveryPrice: pnl.currentDeliveryPrice,
                    snapshotSpread: currentSpread,
                    snapshotTime: Date.now()
                }
            };
        }
        
        // ✅ 只保留止损,去掉止盈
        if (pnl.totalPnlRate <= -CONFIG.stopLossRate) {
            return {
                should: true,
                reason: '🛑 达到止损线(需二次确认)',
                detail: `实时亏损 ${(pnl.totalPnlRate*100).toFixed(4)}% <= ${(-CONFIG.stopLossRate*100).toFixed(2)}%`,
                needsConfirmation: true,  // ✅ 标记需要二次确认
                priceSnapshot: {
                    snapshotSpotPrice: pnl.currentSpotPrice,
                    snapshotDeliveryPrice: pnl.currentDeliveryPrice,
                    snapshotSpread: currentSpread,
                    snapshotTime: Date.now()
                }
            };
        }
        
        // 临近交割
        if (currentPair.daysToDelivery < 1) {
            return {
                should: true,
                reason: '⏰ 临近交割',
                detail: `剩余 ${currentPair.daysToDelivery.toFixed(1)} 天 | 实时盈亏: ${(pnl.totalPnlRate*100).toFixed(4)}%`,
                priceSnapshot: {
                    snapshotSpotPrice: pnl.currentSpotPrice,
                    snapshotDeliveryPrice: pnl.currentDeliveryPrice,
                    snapshotSpread: currentSpread,
                    snapshotTime: Date.now()
                }
            };
        }
        
        // 持仓过久
        if (record.openTime) {
            let holdDays = (Date.now() - record.openTime) / (1000 * 60 * 60 * 24);
            if (holdDays > CONFIG.maxHoldDays && pnl.totalPnlRate > 0) {
                return {
                    should: true,
                    reason: '⏳ 持仓过久',
                    detail: `持仓 ${holdDays.toFixed(1)} 天 > ${CONFIG.maxHoldDays} 天 | 盈利${(pnl.totalPnlRate*100).toFixed(4)}%`,
                    priceSnapshot: {
                        snapshotSpotPrice: pnl.currentSpotPrice,
                        snapshotDeliveryPrice: pnl.currentDeliveryPrice,
                        snapshotSpread: currentSpread,
                        snapshotTime: Date.now()
                    }
                };
            }
        }
        
        return { should: false };
    },

    /**
     * 计算实时盈亏
     */
    calculateUnrealizedPnL: function(record, currentPair) {
        if (!record || !currentPair) return null;
        
        let currentSpotPrice = DataLayer.getDepthMidPrice(exchanges[0], currentPair.spotSymbol);
        let currentDeliveryPrice = DataLayer.getDepthMidPrice(exchanges[1], currentPair.deliverySymbol);
        
        if (!currentSpotPrice || !currentDeliveryPrice) {
            currentSpotPrice = currentPair.spotPrice;
            currentDeliveryPrice = currentPair.deliveryPrice;
        }
        
        let spotReturnRate = 0;
        let deliveryReturnRate = 0;
        
        if (record.direction === 'positive') {
            spotReturnRate = (currentSpotPrice - record.openSpotPrice) / record.openSpotPrice;
            deliveryReturnRate = (record.openDeliveryPrice - currentDeliveryPrice) / record.openDeliveryPrice;
        } else {
            spotReturnRate = (record.openSpotPrice - currentSpotPrice) / record.openSpotPrice;
            deliveryReturnRate = (currentDeliveryPrice - record.openDeliveryPrice) / record.openDeliveryPrice;
        }
        
        let totalReturnRate = spotReturnRate + deliveryReturnRate;
        let requiredUSD = record.openSpotPrice * record.spotAmount;
        let totalPnl = totalReturnRate * requiredUSD;
        
        return {
            totalPnl: totalPnl,
            totalPnlRate: totalReturnRate,
            spotReturnRate: spotReturnRate,
            deliveryReturnRate: deliveryReturnRate,
            spotPnl: spotReturnRate * requiredUSD,
            deliveryPnl: deliveryReturnRate * requiredUSD,
            currentSpotPrice: currentSpotPrice,
            currentDeliveryPrice: currentDeliveryPrice
        };
    }
};

// ==================== 执行层 (ExecutionLayer) ====================
const ExecutionLayer = {
    /**
     * 检查现货账户余额
     */
    checkSpotBalance: function(pair, direction, amount, currentPrice) {
        Log('🔍 检查现货账户余额...');
        
        for (let attempt = 1; attempt <= CONFIG.balanceCheckRetries; attempt++) {
            try {
                exchanges[0].SetCurrency(pair.spotSymbol);
                let account = exchanges[0].GetAccount();
                
                if (!account) {
                    if (attempt < CONFIG.balanceCheckRetries) {
                        Log(`⚠️ 获取账户信息失败,第${attempt}次重试...`);
                        Sleep(500);
                        continue;
                    }
                    Log('❌ 无法获取现货账户信息');
                    return { 
                        success: false, 
                        reason: '无法获取账户信息',
                        canRetry: true
                    };
                }
                
                if (direction === 'buy') {
                    let requiredUSDT = amount * currentPrice;
                    let availableUSDT = account.Balance;
                    
                    Log(`  操作类型: 买入${pair.coin}`);
                    Log(`  需要USDT: ${requiredUSDT.toFixed(4)}`);
                    Log(`  可用USDT: ${availableUSDT.toFixed(4)}`);
                    Log(`  保留USDT: ${CONFIG.minUSDTReserve.toFixed(4)}`);
                    
                    if (availableUSDT < requiredUSDT + CONFIG.minUSDTReserve) {
                        Log(`⚠️ USDT余额不足,无法买入`);
                        Log(`  缺口: ${(requiredUSDT + CONFIG.minUSDTReserve - availableUSDT).toFixed(4)} USDT`);
                        Log(`  💡 策略提示:将等待卖出方向的套利机会`);
                        return { 
                            success: false, 
                            reason: `USDT不足(需要${requiredUSDT.toFixed(2)}, 可用${availableUSDT.toFixed(2)})`,
                            insufficientDirection: 'buy',
                            canRetry: false
                        };
                    }
                    
                    Log(`✅ USDT余额充足`);
                    return { success: true };
                    
                } else if (direction === 'sell') {
                    let requiredCoin = amount;
                    let availableCoin = account.Stocks;
                    
                    Log(`  操作类型: 卖出${pair.coin}`);
                    Log(`  需要${pair.coin}: ${requiredCoin.toFixed(6)}`);
                    Log(`  可用${pair.coin}: ${availableCoin.toFixed(6)}`);
                    
                    if (availableCoin < requiredCoin) {
                        Log(`⚠️ ${pair.coin}余额不足,无法卖出`);
                        Log(`  缺口: ${(requiredCoin - availableCoin).toFixed(6)} ${pair.coin}`);
                        Log(`  💡 策略提示:将等待买入方向的套利机会`);
                        return { 
                            success: false, 
                            reason: `${pair.coin}不足(需要${requiredCoin.toFixed(6)}, 可用${availableCoin.toFixed(6)})`,
                            insufficientDirection: 'sell',
                            canRetry: false
                        };
                    }
                    
                    Log(`✅ ${pair.coin}余额充足`);
                    return { success: true };
                }
                
            } catch(e) {
                if (attempt < CONFIG.balanceCheckRetries) {
                    Log(`⚠️ 检查余额异常(第${attempt}次): ${e.message},正在重试...`);
                    Sleep(500);
                    continue;
                }
                Log(`❌ 检查余额异常: ${e.message}`);
                return { 
                    success: false, 
                    reason: '检查余额异常: ' + e.message,
                    canRetry: true
                };
            }
        }
        
        return { 
            success: false, 
            reason: '检查余额超时',
            canRetry: true
        };
    },

    /**
     * 通用下单函数
     */
    createOrderWithFallback: function(exchange, symbol, direction, amount, limitPrice, orderType, maxRetry = 3) {
        let orderId = null;
        let order = null;
        let retryCount = 0;
        let useMarketOrder = (limitPrice === -1);
        let isSpotBuy = (orderType === 'spot' || orderType === '现货') && direction === 'buy';
        
        function getActualAmount(useMarket) {
            if (isSpotBuy && useMarket) {
                let currentPrice = DataLayer.getDepthMidPrice(exchange, symbol);
                if (!currentPrice) {
                    Log(`❌ 无法获取${symbol}盘口价格用于计算USDT金额`);
                    return 0;
                }
                let usdtAmount = amount * currentPrice;
                Log(`  💡 现货买单转换: ${amount.toFixed(6)} 币 → ${usdtAmount.toFixed(4)} USDT (Depth价格${currentPrice.toFixed(2)})`);
                return usdtAmount;
            }
            return amount;
        }
        
        if (!useMarketOrder) {
            let orderAmount = amount;
            Log(`📝 提交${orderType}限价${direction}单: 价格=${limitPrice.toFixed(2)}, 数量=${orderAmount.toFixed(6)}`);
            orderId = exchange.CreateOrder(symbol, direction, limitPrice, orderAmount);
            
            if (!orderId) {
                Log(`❌ ${orderType}限价单提交失败,改用市价单`);
                useMarketOrder = true;
            } else {
                Log(`✅ ${orderType}限价单已提交, OrderId:`, orderId);
            }
        }
        
        if (useMarketOrder && !orderId) {
            let marketAmount = getActualAmount(true);
            if (marketAmount === 0) return null;
            
            Log(`📝 提交${orderType}市价${direction}单, 数量=${marketAmount.toFixed(6)}`);
            orderId = exchange.CreateOrder(symbol, direction, -1, marketAmount);
            
            if (!orderId) {
                Log(`❌ ${orderType}市价单提交失败`);
                return null;
            }
            Log(`✅ ${orderType}市价单已提交, OrderId:`, orderId);
        }
        
        Sleep(3000);
        order = exchange.GetOrder(orderId);
        
        while ((!order || order.Status === 2 || order.Status === 3) && retryCount < maxRetry) {
            retryCount++;
            
            if (!order) {
                Log(`⚠️ 无法获取订单状态,第${retryCount}/${maxRetry}次重试...`);
            } else if (order.Status === 2) {
                Log(`⚠️ 订单被撤销,第${retryCount}/${maxRetry}次重试...`);
            } else if (order.Status === 3) {
                Log(`⚠️ 订单状态未知,第${retryCount}/${maxRetry}次重试...`);
            }
            
            let retryAmount = getActualAmount(true);
            if (retryAmount === 0) return null;
            
            Log(`🔄 重试使用市价单, 数量=${retryAmount.toFixed(6)}`);
            orderId = exchange.CreateOrder(symbol, direction, -1, retryAmount);
            
            if (!orderId) {
                Log(`❌ 第${retryCount}次重试下单失败`);
                Sleep(2000);
                continue;
            }
            
            Sleep(3000);
            order = exchange.GetOrder(orderId);
            
            if (order && order.Status === 1) {
                Log(`✅ 第${retryCount}次重试成功`);
                break;
            }
            
            if (order) {
                Log(`❌ 第${retryCount}次重试订单状态: ${order.Status}`);
            }
        }
        
        if (!order) {
            Log(`❌ ${orderType}订单无法获取,最终失败`);
            return null;
        }
        
        if (order.Status !== 1) {
            Log(`❌ ${orderType}订单最终未成交,状态: ${order.Status}`);
            
            let currentPrice = DataLayer.getDepthMidPrice(exchange, order.Symbol);
            if (currentPrice > 0) {
                Log(`  当前市场价格(Depth): ${currentPrice.toFixed(2)}`);
                if (order.Price && order.Price > 0) {
                    Log(`  订单价格: ${order.Price.toFixed(2)}`);
                    Log(`  价格偏差: ${((order.Price - currentPrice) / currentPrice * 100).toFixed(3)}%`);
                }
            }
            
            if (order.Status === 0) {
                Log(`⚠️ 订单仍在等待中,尝试撤销...`);
                exchange.CancelOrder(orderId);
            }
            return null;
        }
        
        Log(`✅ ${orderType}订单最终成交`);
        return order;
    },

    /**
     * 获取期货持仓
     */
    getActualPositions: function() {
        let futurePositions = exchanges[1].GetPositions('USDT.futures');
        if (!futurePositions) futurePositions = [];
        return futurePositions;
    },

    /**
     * 根据Symbol获取持仓
     */
    getPositionBySymbol: function(deliverySymbol) {
        let allPositions = ExecutionLayer.getActualPositions();
        for (let pos of allPositions) {
            if (Math.abs(pos.Amount) <= 0) continue;
            if (pos.Symbol === deliverySymbol) return pos;
        }
        return null;
    },

    /**
     * 计算合约数量
     */
    calculateContractAmount: function(spotAmount, ctVal) {
        let contractAmount = spotAmount / ctVal;
        contractAmount = Math.floor(contractAmount);
        if (contractAmount < 1) contractAmount = 1;
        return contractAmount;
    },

    /**
     * 冷却期管理
     */
    addCooldown: function(deliverySymbol, coin, reason) {
        pairCooldowns[deliverySymbol] = Date.now() + CONFIG.cooldownDuration;
        Log(`⏸️ ${deliverySymbol} 进入10分钟冷却期`);
        Log(`   原因: ${reason}`);
        _G('pairCooldowns', pairCooldowns);
    },

    checkCooldown: function(deliverySymbol, coin) {
        if (pairCooldowns[deliverySymbol]) {
            let cooldownEnd = pairCooldowns[deliverySymbol];
            let now = Date.now();
            if (now < cooldownEnd) {
                return true;
            } else {
                delete pairCooldowns[deliverySymbol];
                _G('pairCooldowns', pairCooldowns);
                return false;
            }
        }
        return false;
    },

    addOpportunityLostCooldown: function(deliverySymbol, reason) {
        opportunityLostCooldowns[deliverySymbol] = Date.now() + CONFIG.opportunityLostCooldown;
        Log(`⏸️ ${deliverySymbol} 套利机会消失,进入1分钟冷却`);
        Log(`   原因: ${reason}`);
        _G('opportunityLostCooldowns', opportunityLostCooldowns);
    },

    checkOpportunityLostCooldown: function(deliverySymbol) {
        if (opportunityLostCooldowns[deliverySymbol]) {
            let cooldownEnd = opportunityLostCooldowns[deliverySymbol];
            let now = Date.now();
            if (now < cooldownEnd) {
                return true;
            } else {
                delete opportunityLostCooldowns[deliverySymbol];
                _G('opportunityLostCooldowns', opportunityLostCooldowns);
                return false;
            }
        }
        return false;
    },

    /**
     * ✅ v5.1新增:回滚现货订单(带Depth价格验证)
     */
    rollbackSpotOrder: function(exchange, pair, direction, amount, reason) {
        Log('-----------------------------------');
        Log('🔄 开始回滚现货订单');
        Log('  币种:', pair.coin);
        Log('  方向:', direction === 'buy' ? '买入' : '卖出');
        Log('  数量:', amount.toFixed(6));
        Log('  原因:', reason);
        
        for (let retry = 1; retry <= CONFIG.maxRollbackRetries; retry++) {
            Log(`🔄 回滚尝试 ${retry}/${CONFIG.maxRollbackRetries}`);
            
            // 1. 获取当前Depth价格
            let currentPrice = DataLayer.getDepthMidPrice(exchange, pair.spotSymbol, true);
            if (!currentPrice) {
                Log(`⚠️ 第${retry}次无法获取Depth价格,等待后重试...`);
                Sleep(1000);
                continue;
            }
            
            // 2. 提交回滚订单(市价单)
            let rollbackOrderId = null;
            if (direction === 'buy') {
                let usdtAmount = amount * currentPrice;
                Log(`  提交市价买单: ${usdtAmount.toFixed(4)} USDT (按Depth价格${currentPrice.toFixed(2)})`);
                rollbackOrderId = exchange.CreateOrder(pair.spotSymbol, 'buy', -1, usdtAmount);
            } else {
                Log(`  提交市价卖单: ${amount.toFixed(6)} ${pair.coin}`);
                rollbackOrderId = exchange.CreateOrder(pair.spotSymbol, 'sell', -1, amount);
            }
            
            if (!rollbackOrderId) {
                Log(`❌ 第${retry}次回滚订单提交失败`);
                Sleep(1000);
                continue;
            }
            
            Log(`  回滚订单已提交: ${rollbackOrderId}`);
            Sleep(2000);
            
            // 3. 检查订单状态
            let rollbackOrder = exchange.GetOrder(rollbackOrderId);
            if (!rollbackOrder) {
                Log(`⚠️ 第${retry}次无法获取回滚订单状态`);
                continue;
            }
            
            Log(`  回滚订单状态: ${rollbackOrder.Status} (0=等待, 1=成交, 2=撤销)`);
            
            if (rollbackOrder.Status === 1) {
                Log('✅ 回滚订单成交');
                DisplayLayer.printOrderDetails(exchange, pair.spotSymbol, rollbackOrderId, '现货回滚订单');
                
                // 4. 验证回滚后仓位
                exchange.SetCurrency(pair.spotSymbol);
                let account = exchange.GetAccount();
                
                if (account) {
                    if (direction === 'buy') {
                        Log(`  回滚后${pair.coin}余额: ${account.Stocks.toFixed(6)}`);
                    } else {
                        Log(`  回滚后USDT余额: ${account.Balance.toFixed(4)}`);
                    }
                }
                
                Log('✅ 现货回滚成功!');
                return true;
            }
            
            if (rollbackOrder.Status === 0) {
                Log(`⚠️ 第${retry}次回滚订单仍在等待,撤销后重试...`);
                exchange.CancelOrder(rollbackOrderId);
                Sleep(1000);
                continue;
            }
            
            if (rollbackOrder.Status === 2) {
                Log(`⚠️ 第${retry}次回滚订单被撤销,重试...`);
                Sleep(1000);
                continue;
            }
        }
        
        Log('❌ 现货回滚失败!已尝试' + CONFIG.maxRollbackRetries + '次');
        return false;
    },

    /**
     * ✅ v5.1新增:回滚期货订单(带Depth价格验证)
     */
    rollbackDeliveryOrder: function(exchange, pair, direction, amount, reason) {
        Log('-----------------------------------');
        Log('🔄 开始回滚期货订单');
        Log('  币种:', pair.coin);
        Log('  方向:', direction === 'closebuy' ? '平多' : '平空');
        Log('  数量:', amount);
        Log('  原因:', reason);
        
        for (let retry = 1; retry <= CONFIG.maxRollbackRetries; retry++) {
            Log(`🔄 回滚尝试 ${retry}/${CONFIG.maxRollbackRetries}`);
            
            // 1. 获取当前Depth价格(用于日志)
            let currentPrice = DataLayer.getDepthMidPrice(exchange, pair.deliverySymbol, true);
            if (currentPrice) {
                Log(`  当前Depth期货价: ${currentPrice.toFixed(2)}`);
            }
            
            // 2. 提交回滚平仓订单(市价单)
            Log(`  提交市价${direction === 'closebuy' ? '平多' : '平空'}单: ${amount} 张`);
            let rollbackOrderId = exchange.CreateOrder(pair.deliverySymbol, direction, -1, amount);
            
            if (!rollbackOrderId) {
                Log(`❌ 第${retry}次回滚订单提交失败`);
                Sleep(1000);
                continue;
            }
            
            Log(`  回滚订单已提交: ${rollbackOrderId}`);
            Sleep(2000);
            
            // 3. 检查订单状态
            let rollbackOrder = exchange.GetOrder(rollbackOrderId);
            if (!rollbackOrder) {
                Log(`⚠️ 第${retry}次无法获取回滚订单状态`);
                Sleep(1000);
                continue;
            }
            
            Log(`  回滚订单状态: ${rollbackOrder.Status} (0=等待, 1=成交, 2=撤销)`);
            
            if (rollbackOrder.Status === 1) {
                Log('✅ 回滚订单成交');
                DisplayLayer.printOrderDetails(exchange, pair.deliverySymbol, rollbackOrderId, '期货回滚订单');
                
                // 4. 验证回滚后仓位
                Sleep(1000);
                let remainingPos = ExecutionLayer.getPositionBySymbol(pair.deliverySymbol);
                
                if (remainingPos && Math.abs(remainingPos.Amount) > 0) {
                    Log(`⚠️ 警告:回滚后仍有残余仓位 ${remainingPos.Amount} 张`);
                } else {
                    Log('✅ 验证:期货仓位已完全平仓');
                }
                
                Log('✅ 期货回滚成功!');
                return true;
            }
            
            if (rollbackOrder.Status === 0) {
                Log(`⚠️ 第${retry}次回滚订单仍在等待,撤销后重试...`);
                exchange.CancelOrder(rollbackOrderId);
                Sleep(1000);
                continue;
            }
            
            if (rollbackOrder.Status === 2) {
                Log(`⚠️ 第${retry}次回滚订单被撤销,重试...`);
                Sleep(1000);
                continue;
            }
        }
        
        Log('❌ 期货回滚失败!已尝试' + CONFIG.maxRollbackRetries + '次');
        return false;
    },

    /**
     * ✅ v5.1改进:开仓执行(使用增强的回滚验证)
     */
    openPosition: function(pair, openCheck) {
        Log('===================================');
        Log('🚀 开始开仓流程');
        Log('===================================');
        
        if (ExecutionLayer.checkCooldown(pair.deliverySymbol, pair.coin)) return false;
        if (ExecutionLayer.checkOpportunityLostCooldown(pair.deliverySymbol)) return false;
        
        // 检查并平掉现有仓位
        Log('🔍 检查期货账户现有仓位...');
        let existingPosition = ExecutionLayer.getPositionBySymbol(pair.deliverySymbol);
        
        if (existingPosition && Math.abs(existingPosition.Amount) > 0) {
            Log('⚠️ 检测到该合约的现有仓位,执行平仓操作...');
            try {
                let closeDirection = existingPosition.Type === PD_LONG ? 'closebuy' : 'closesell';
                let closeAmount = Math.abs(existingPosition.Amount);
                let closeOrder = ExecutionLayer.createOrderWithFallback(
                    exchanges[1], pair.deliverySymbol, closeDirection, closeAmount, -1, '期货'
                );
                
                if (!closeOrder) {
                    Log('❌ 平仓现有持仓失败,终止开仓');
                    ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '平仓现有持仓失败');
                    return false;
                }
                Log('✅ 成功平仓现有持仓');
                Sleep(2000);
            } catch (e) {
                Log('❌ 平仓现有持仓异常:', e.message);
                ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '平仓现有持仓异常');
                return false;
            }
        } else {
            Log('✅ 期货账户无现有仓位,可以开仓');
        }
        
        // 二次验证套利机会
        Log('🔄 重新获取实时Depth盘口价格并验证套利机会...');
        Log('-----------------------------------');
        
        let realtimeSpotPrice = DataLayer.getDepthMidPrice(exchanges[0], pair.spotSymbol, true);
        let realtimeDeliveryPrice = DataLayer.getDepthMidPrice(exchanges[1], pair.deliverySymbol, true);
        
        if (!realtimeSpotPrice || !realtimeDeliveryPrice) {
            Log('❌ 获取实时Depth盘口价格失败,开仓终止');
            ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '获取实时Depth价格失败');
            return false;
        }
        
        let realtimeSpread = realtimeDeliveryPrice - realtimeSpotPrice;
        let realtimeSpreadRate = realtimeSpread / realtimeSpotPrice;
        
        Log('📊 价格对比(信号时 vs 实时Depth):');
        Log('  信号时现货价:', openCheck.priceSnapshot.spotPrice.toFixed(2), 
            '→ 实时Depth现货价:', realtimeSpotPrice.toFixed(2),
            '| 偏差:', ((realtimeSpotPrice - openCheck.priceSnapshot.spotPrice) / openCheck.priceSnapshot.spotPrice * 100).toFixed(3), '%');
        Log('  信号时期货价:', openCheck.priceSnapshot.deliveryPrice.toFixed(2), 
            '→ 实时Depth期货价:', realtimeDeliveryPrice.toFixed(2),
            '| 偏差:', ((realtimeDeliveryPrice - openCheck.priceSnapshot.deliveryPrice) / openCheck.priceSnapshot.deliveryPrice * 100).toFixed(3), '%');
        
        let history = priceHistory[pair.deliverySymbol];
        if (!history || history.length < CONFIG.minHistoryForTest) {
            Log('❌ 历史数据不足,无法验证');
            return false;
        }
        
        let mu = openCheck.openMean;
        let sigma = openCheck.openStd;
        let realtimeZScore = (realtimeSpreadRate - mu) / (sigma || 1e-6);
        
        Log('📈 Z-Score 对比:');
        Log('  信号时 Z-Score:', openCheck.openZScore.toFixed(2));
        Log('  实时Depth Z-Score:', realtimeZScore.toFixed(2));
        
        let absRealtimeZ = Math.abs(realtimeZScore);
        if (absRealtimeZ < CONFIG.zScoreEntry) {
            Log('❌ 套利机会已消失!');
            Log(`  实时Depth |Z-Score| = ${absRealtimeZ.toFixed(2)} < ${CONFIG.zScoreEntry}`);
            ExecutionLayer.addOpportunityLostCooldown(pair.deliverySymbol, `Z-Score不足: ${absRealtimeZ.toFixed(2)} < ${CONFIG.zScoreEntry}`);
            return false;
        }
        
        let realtimeDirection = realtimeZScore > 0 ? 'positive' : 'negative';
        if (realtimeDirection !== openCheck.direction) {
            Log('❌ 价差方向已反转!');
            ExecutionLayer.addOpportunityLostCooldown(pair.deliverySymbol, `方向反转: ${openCheck.direction} → ${realtimeDirection}`);
            return false;
        }
        
        Log('✅ 实时Depth验证通过,套利机会仍然存在');
        
        // 开仓前检查现货余额
        Log('-----------------------------------');
        let spotAmount = CONFIG.orderAmount;
        let spotDirection = realtimeDirection === 'positive' ? 'buy' : 'sell';
        let balanceCheck = ExecutionLayer.checkSpotBalance(pair, spotDirection, spotAmount, realtimeSpotPrice);
        
        if (!balanceCheck.success) {
            Log('⚠️ 现货余额不足,本次开仓跳过');
            Log('   原因:', balanceCheck.reason);
            
            if (balanceCheck.insufficientDirection === 'buy') {
                Log('   💡 当前无法执行买入现货,将等待卖出现货的套利机会');
            } else if (balanceCheck.insufficientDirection === 'sell') {
                Log('   💡 当前无法执行卖出现货,将等待买入现货的套利机会');
            }
            
            if (balanceCheck.canRetry) {
                Log('   ⚠️ 检查余额异常,触发10分钟冷却');
                ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '余额检查异常: ' + balanceCheck.reason);
            }
            
            return false;
        }
        Log('-----------------------------------');
        
        // 计算开仓参数
        let direction = realtimeDirection;
        let targetSpreadRateUpper = mu + CONFIG.zScoreExitTarget * sigma;
        let targetSpreadRateLower = mu - CONFIG.zScoreExitTarget * sigma;
        let targetSpreadUpper = targetSpreadRateUpper * realtimeSpotPrice;
        let targetSpreadLower = targetSpreadRateLower * realtimeSpotPrice;
        
        let spreads = history.slice(-100).map(h => h.spread);
        let avgSpread = spreads.reduce((a, b) => a + b, 0) / spreads.length;
        
        let deviation = SignalLayer.detectPriceDeviation(pair, {zScore: realtimeZScore});
        
        let spreadDeviation = realtimeSpread - avgSpread;
        let spreadStd = sigma * realtimeSpotPrice;
        let adjustmentRatio = Math.min(
            Math.abs(spreadDeviation) * CONFIG.limitOrderSpreadRatio,
            spreadStd * 0.5
        );
        
        let minAdjustment = realtimeSpotPrice * 0.0005;
        let maxAdjustment = realtimeSpotPrice * 0.005;
        adjustmentRatio = Math.max(minAdjustment, Math.min(maxAdjustment, adjustmentRatio));
        
        let spotLimitPrice = 0;
        let deliveryLimitPrice = 0;
        
        if (direction === 'positive') {
            spotLimitPrice = realtimeSpotPrice + adjustmentRatio;
            deliveryLimitPrice = realtimeDeliveryPrice - adjustmentRatio;
        } else {
            spotLimitPrice = realtimeSpotPrice - adjustmentRatio;
            deliveryLimitPrice = realtimeDeliveryPrice + adjustmentRatio;
        }
        
        Log('📝 限价单价格(基于Depth+调整):');
        Log('  现货挂单价:', spotLimitPrice.toFixed(2));
        Log('  期货挂单价:', deliveryLimitPrice.toFixed(2));
        
        let firstIsSpot = deviation.isSpotDeviation || (!deviation.isDeliveryDeviation);
        Log('🎯 开仓策略:', direction === 'positive' ? '正套(价差过大)' : '反套(价差过小)');
        Log('🎯 执行顺序:', firstIsSpot ? '先开现货' : '先开期货');
        Log('===================================');
        
        let contractAmount = ExecutionLayer.calculateContractAmount(spotAmount, pair.ctVal);
        
        try {
            let spotOrder = null;
            let deliveryOrder = null;
            
            exchanges[1].SetMarginLevel(CONFIG.marginLevel);
            
            // ==================== 正套开仓 ====================
            if (direction === 'positive') {
                if (firstIsSpot) {
                    // 先开现货买单
                    spotOrder = ExecutionLayer.createOrderWithFallback(
                        exchanges[0], pair.spotSymbol, 'buy', spotAmount, spotLimitPrice, '现货'
                    );
                    if (!spotOrder) {
                        Log('❌ 现货买单失败,开仓终止');
                        ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '现货买单失败');
                        return false;
                    }
                    DisplayLayer.printOrderDetails(exchanges[0], pair.spotSymbol, spotOrder.Id, '现货买入订单');
                    
                    // 再开期货卖单
                    deliveryOrder = ExecutionLayer.createOrderWithFallback(
                        exchanges[1], pair.deliverySymbol, 'sell', contractAmount, deliveryLimitPrice, '期货'
                    );
                    if (!deliveryOrder) {
                        Log('❌ 期货卖单失败,需要回滚现货');
                        // ✅ v5.1: 使用增强的回滚验证
                        if (!ExecutionLayer.rollbackSpotOrder(exchanges[0], pair, 'sell', spotAmount, '期货卖单失败')) {
                            Log('❌ 回滚现货失败!可能留有残余仓位,请手动检查');
                            ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '期货卖单失败且回滚失败');
                            return false;
                        }
                        ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '期货卖单失败,已成功回滚现货');
                        return false;
                    }
                    DisplayLayer.printOrderDetails(exchanges[1], pair.deliverySymbol, deliveryOrder.Id, '期货卖出订单');
                    
                } else {
                    // 先开期货卖单
                    deliveryOrder = ExecutionLayer.createOrderWithFallback(
                        exchanges[1], pair.deliverySymbol, 'sell', contractAmount, deliveryLimitPrice, '期货'
                    );
                    if (!deliveryOrder) {
                        Log('❌ 期货卖单失败,开仓终止');
                        ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '期货卖单失败');
                        return false;
                    }
                    DisplayLayer.printOrderDetails(exchanges[1], pair.deliverySymbol, deliveryOrder.Id, '期货卖出订单');
                    
                    // 再开现货买单
                    spotOrder = ExecutionLayer.createOrderWithFallback(
                        exchanges[0], pair.spotSymbol, 'buy', spotAmount, spotLimitPrice, '现货'
                    );
                    if (!spotOrder) {
                        Log('❌ 现货买单失败,需要回滚期货');
                        // ✅ v5.1: 使用增强的回滚验证
                        if (!ExecutionLayer.rollbackDeliveryOrder(exchanges[1], pair, 'closesell', contractAmount, '现货买单失败')) {
                            Log('❌ 回滚期货失败!可能留有残余仓位,请手动检查');
                            ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '现货买单失败且回滚失败');
                            return false;
                        }
                        ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '现货买单失败,已成功回滚期货');
                        return false;
                    }
                    DisplayLayer.printOrderDetails(exchanges[0], pair.spotSymbol, spotOrder.Id, '现货买入订单');
                }
                
            // ==================== 反套开仓 ====================
            } else {
                if (firstIsSpot) {
                    // 先开现货卖单
                    spotOrder = ExecutionLayer.createOrderWithFallback(
                        exchanges[0], pair.spotSymbol, 'sell', spotAmount, spotLimitPrice, '现货'
                    );
                    if (!spotOrder) {
                        Log('❌ 现货卖单失败,开仓终止');
                        ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '现货卖单失败');
                        return false;
                    }
                    DisplayLayer.printOrderDetails(exchanges[0], pair.spotSymbol, spotOrder.Id, '现货卖出订单');
                    
                    // 再开期货买单
                    deliveryOrder = ExecutionLayer.createOrderWithFallback(
                        exchanges[1], pair.deliverySymbol, 'buy', contractAmount, deliveryLimitPrice, '期货'
                    );
                    if (!deliveryOrder) {
                        Log('❌ 期货买单失败,需要回滚现货');
                        // ✅ v5.1: 使用增强的回滚验证
                        if (!ExecutionLayer.rollbackSpotOrder(exchanges[0], pair, 'buy', spotAmount, '期货买单失败')) {
                            Log('❌ 回滚现货失败!可能留有残余仓位,请手动检查');
                            ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '期货买单失败且回滚失败');
                            return false;
                        }
                        ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '期货买单失败,已成功回滚现货');
                        return false;
                    }
                    DisplayLayer.printOrderDetails(exchanges[1], pair.deliverySymbol, deliveryOrder.Id, '期货买入订单');
                    
                } else {
                    // 先开期货买单
                    deliveryOrder = ExecutionLayer.createOrderWithFallback(
                        exchanges[1], pair.deliverySymbol, 'buy', contractAmount, deliveryLimitPrice, '期货'
                    );
                    if (!deliveryOrder) {
                        Log('❌ 期货买单失败,开仓终止');
                        ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '期货买单失败');
                        return false;
                    }
                    DisplayLayer.printOrderDetails(exchanges[1], pair.deliverySymbol, deliveryOrder.Id, '期货买入订单');
                    
                    // 再开现货卖单
                    spotOrder = ExecutionLayer.createOrderWithFallback(
                        exchanges[0], pair.spotSymbol, 'sell', spotAmount, spotLimitPrice, '现货'
                    );
                    if (!spotOrder) {
                        Log('❌ 现货卖单失败,需要回滚期货');
                        // ✅ v5.1: 使用增强的回滚验证
                        if (!ExecutionLayer.rollbackDeliveryOrder(exchanges[1], pair, 'closebuy', contractAmount, '现货卖单失败')) {
                            Log('❌ 回滚期货失败!可能留有残余仓位,请手动检查');
                            ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '现货卖单失败且回滚失败');
                            return false;
                        }
                        ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '现货卖单失败,已成功回滚期货');
                        return false;
                    }
                    DisplayLayer.printOrderDetails(exchanges[0], pair.spotSymbol, spotOrder.Id, '现货卖出订单');
                }
            }
            
            let openSpotPrice = spotOrder.AvgPrice || spotLimitPrice;
            let openDeliveryPrice = deliveryOrder.AvgPrice || deliveryLimitPrice;
            let openSpread = openDeliveryPrice - openSpotPrice;
            let openSpreadRate = openSpread / openSpotPrice;
            
            // 动态调整目标区间
            Log('-----------------------------------');
            Log('🔧 根据实际成交价差动态调整目标区间:');
            Log('  初始目标区间: [', targetSpreadLower.toFixed(2), ',', targetSpreadUpper.toFixed(2), ']');
            Log('  实际成交价差:', openSpread.toFixed(2));
            
            let minProfitDistance = CONFIG.useFixedProfitSpace 
                ? CONFIG.minProfitSpaceUSDT 
                : openSpotPrice * CONFIG.minProfitSpaceRate;
            
            Log(`  最小盈利空间要求: ${minProfitDistance.toFixed(2)} USDT`);
            
            let adjustmentNeeded = false;
            let originalTargetLower = targetSpreadLower;
            let originalTargetUpper = targetSpreadUpper;
            let targetRangeWidth = originalTargetUpper - originalTargetLower;
            
            if (direction === 'positive') {
                let distanceToTarget = openSpread - targetSpreadLower;
                Log('  正套策略:需要价差缩小到目标下限');
                Log(`  当前距离目标下限: ${distanceToTarget.toFixed(2)} USDT`);
                
                if (distanceToTarget < minProfitDistance) {
                    adjustmentNeeded = true;
                    let adjustment = minProfitDistance - distanceToTarget;
                    targetSpreadLower = openSpread - minProfitDistance;
                    targetSpreadUpper = targetSpreadLower + targetRangeWidth;
                    Log('  ⚠️ 成交价差过于接近原目标区间,需要向下调整');
                    Log(`  调整幅度: -${adjustment.toFixed(2)} USDT`);
                } else {
                    Log('  ✅ 成交价差合理,保持原目标区间');
                }
            } else {
                let distanceToTarget = targetSpreadUpper - openSpread;
                Log('  反套策略:需要价差扩大到目标上限');
                Log(`  当前距离目标上限: ${distanceToTarget.toFixed(2)} USDT`);
                
                if (distanceToTarget < minProfitDistance) {
                    adjustmentNeeded = true;
                    let adjustment = minProfitDistance - distanceToTarget;
                    targetSpreadUpper = openSpread + minProfitDistance;
                    targetSpreadLower = targetSpreadUpper - targetRangeWidth;
                    Log('  ⚠️ 成交价差过于接近原目标区间,需要向上调整');
                    Log(`  调整幅度: +${adjustment.toFixed(2)} USDT`);
                } else {
                    Log('  ✅ 成交价差合理,保持原目标区间');
                }
            }
            
            if (adjustmentNeeded) {
                Log('  调整后目标区间: [', targetSpreadLower.toFixed(2), ',', targetSpreadUpper.toFixed(2), ']');
            }
            
            Log('===================================');
            Log('✅ 开仓成功!');
            Log('===================================');
            Log('💰 成交信息:');
            Log('  成交现货价:', openSpotPrice.toFixed(2));
            Log('  成交期货价:', openDeliveryPrice.toFixed(2));
            Log('  成交价差:', openSpread.toFixed(4), `(${(openSpreadRate*100).toFixed(3)}%)`);
            Log('  最终目标平仓区间: [', targetSpreadLower.toFixed(2), ',', targetSpreadUpper.toFixed(2), ']');
            if (adjustmentNeeded) {
                Log('  ✅ (已根据成交价差动态调整)');
            }
            Log('===================================');
            
            positionRecords[pair.deliverySymbol] = {
                coin: pair.coin,
                spotSymbol: pair.spotSymbol,
                deliverySymbol: pair.deliverySymbol,
                deliveryType: pair.deliveryType,
                deliveryTypeName: pair.deliveryTypeName,
                direction: direction,
                deviation: deviation,
                openTime: Date.now(),
                openSpotPrice: openSpotPrice,
                openDeliveryPrice: openDeliveryPrice,
                openSpread: openSpread,
                openSpreadRate: openSpreadRate,
                openZScore: realtimeZScore,
                openMean: mu,
                openStd: sigma,
                targetSpreadUpper: targetSpreadUpper,
                targetSpreadLower: targetSpreadLower,
                originalTargetUpper: originalTargetUpper,
                originalTargetLower: originalTargetLower,
                targetAdjusted: adjustmentNeeded,
                spotAmount: spotAmount,
                contractAmount: contractAmount,
                ctVal: pair.ctVal,
                spotOrderId: spotOrder.Id,
                deliveryOrderId: deliveryOrder.Id
            };
            
            _G('positionRecords', positionRecords);
            return true;
            
        } catch (e) {
            Log('❌ 开仓异常:', e.message);
            ExecutionLayer.addCooldown(pair.deliverySymbol, pair.coin, '开仓异常: ' + e.message);
            return false;
        }
    },

    /**
     * 平仓执行(带止损二次确认)
     */
    closePosition: function(deliverySymbol, currentPair, closeReason) {
        Log('===================================');
        Log('🚀 开始平仓流程');
        Log('===================================');
        Log('币种:', currentPair.coin);
        Log('交割合约:', deliverySymbol);
        Log('平仓原因:', closeReason.reason);
        Log('详细信息:', closeReason.detail);
        
        let record = positionRecords[deliverySymbol];
        if (!record) {
            Log('❌ 未找到开仓记录');
            return false;
        }
        
        let snapshot = closeReason.priceSnapshot;
        if (snapshot) {
            Log('-----------------------------------');
            Log('📸 平仓信号快照:');
            Log('  快照时间:', new Date(snapshot.snapshotTime).toLocaleString());
            Log('  现货Depth:', snapshot.snapshotSpotPrice.toFixed(2));
            Log('  期货Depth:', snapshot.snapshotDeliveryPrice.toFixed(2));
            Log('  价差:', snapshot.snapshotSpread.toFixed(2));
        }
        
        // ✅ 止损二次确认
        if (closeReason.needsConfirmation && closeReason.reason.includes('止损')) {
            Log('-----------------------------------');
            Log('🔄 止损二次确认:重新计算实时盈亏...');
            Sleep(500);
            
            let verifyPnl = SignalLayer.calculateUnrealizedPnL(record, currentPair);
            if (!verifyPnl) {
                Log('❌ 无法获取实时盈亏,取消平仓');
                ExecutionLayer.addOpportunityLostCooldown(deliverySymbol, '止损二次确认失败');
                return false;
            }
            
            Log('  初次判断盈亏率:', (snapshot ? '(从快照)' : ''), '需验证');
            Log('  实时验证盈亏率:', (verifyPnl.totalPnlRate * 100).toFixed(4), '%');
            Log('  止损线:', (-CONFIG.stopLossRate * 100).toFixed(2), '%');
            
            if (verifyPnl.totalPnlRate > -CONFIG.stopLossRate) {
                Log('✅ 二次确认:盈亏已回升,取消止损平仓');
                Log(`  当前盈亏 ${(verifyPnl.totalPnlRate*100).toFixed(4)}% > 止损线 ${(-CONFIG.stopLossRate*100).toFixed(2)}%`);
                ExecutionLayer.addOpportunityLostCooldown(deliverySymbol, '止损二次确认未通过,盈亏回升');
                return false;
            }
            
            Log('❌ 二次确认:止损条件仍然满足,继续平仓');
            Log(`  当前盈亏 ${(verifyPnl.totalPnlRate*100).toFixed(4)}% <= 止损线 ${(-CONFIG.stopLossRate*100).toFixed(2)}%`);
        }
        
        // 二次验证最新Depth价格
        Log('-----------------------------------');
        Log('🔄 二次验证:获取最新Depth价格...');
        Sleep(100);
        
        let verifySpotPrice = DataLayer.getDepthMidPrice(exchanges[0], record.spotSymbol, true);
        let verifyDeliveryPrice = DataLayer.getDepthMidPrice(exchanges[1], record.deliverySymbol, true);
        
        if (!verifySpotPrice || !verifyDeliveryPrice) {
            Log('❌ 二次验证:获取Depth价格失败');
            ExecutionLayer.addOpportunityLostCooldown(deliverySymbol, '平仓前二次验证Depth获取失败');
            return false;
        }
        
        let verifySpread = verifyDeliveryPrice - verifySpotPrice;
        Log('✅ 二次验证Depth价格:');
        Log('  验证现货价:', verifySpotPrice.toFixed(2));
        Log('  验证期货价:', verifyDeliveryPrice.toFixed(2));
        Log('  验证价差:', verifySpread.toFixed(2));
        
        // 验证价格是否仍然有利(仅针对价差回归)
        let shouldProceed = false;
        
        if (closeReason.reason === '✅ 价差回归目标区间') {
            if (verifySpread >= record.targetSpreadLower && 
                verifySpread <= record.targetSpreadUpper) {
                shouldProceed = true;
                Log('✅ 验证通过:价差仍在目标区间');
            } else {
                let lowerTolerance = record.targetSpreadLower - CONFIG.spreadTolerance;
                let upperTolerance = record.targetSpreadUpper + CONFIG.spreadTolerance;
                
                if (verifySpread >= lowerTolerance && verifySpread <= upperTolerance) {
                    shouldProceed = true;
                    Log('⚠️ 验证通过(容忍范围内):价差略微偏离但可接受');
                } else {
                    shouldProceed = false;
                    Log('❌ 验证失败:价差已偏离目标区间过多');
                }
            }
            
            if (!shouldProceed) {
                ExecutionLayer.addOpportunityLostCooldown(deliverySymbol, `价差偏离目标区间: ${verifySpread.toFixed(2)}`);
                return false;
            }
        } else {
            shouldProceed = true;
            Log('✅ 非价差回归平仓,直接执行');
        }
        
        // 执行平仓
        Log('-----------------------------------');
        Log('📋 平仓策略:');
        if (record.direction === 'positive') {
            Log('  正套平仓:先卖现货 → 后平期货空单');
        } else {
            Log('  反套平仓:先平期货多单 → 后买现货');
        }
        
        try {
            let spotOrderId = null;
            let deliveryOrderId = null;
            let spotOrder = null;
            let deliveryOrder = null;
            
            Log('-----------------------------------');
            Log('⚡ 并发提交平仓订单...');
            
            if (record.direction === 'positive') {
                spotOrderId = exchanges[0].CreateOrder(record.spotSymbol, 'sell', -1, record.spotAmount);
                if (!spotOrderId) {
                    Log('❌ 现货卖单提交失败');
                    return false;
                }
                Log(`✅ 现货卖单已提交: ${spotOrderId}`);
                
                deliveryOrderId = exchanges[1].CreateOrder(record.deliverySymbol, 'closesell', -1, record.contractAmount);
                if (!deliveryOrderId) {
                    Log('❌ 期货平空单提交失败');
                    return false;
                }
                Log(`✅ 期货平空单已提交: ${deliveryOrderId}`);
            } else {
                deliveryOrderId = exchanges[1].CreateOrder(record.deliverySymbol, 'closebuy', -1, record.contractAmount);
                if (!deliveryOrderId) {
                    Log('❌ 期货平多单提交失败');
                    return false;
                }
                Log(`✅ 期货平多单已提交: ${deliveryOrderId}`);
                
                let currentPrice = DataLayer.getDepthMidPrice(exchanges[0], record.spotSymbol);
                if (!currentPrice) currentPrice = verifySpotPrice;
                let usdtAmount = record.spotAmount * currentPrice;
                
                spotOrderId = exchanges[0].CreateOrder(record.spotSymbol, 'buy', -1, usdtAmount);
                if (!spotOrderId) {
                    Log('❌ 现货买单提交失败');
                    return false;
                }
                Log(`✅ 现货买单已提交: ${spotOrderId}`);
            }
            
            // 轮询检查订单状态
            Log('-----------------------------------');
            Log('⏱️ 轮询检查订单状态(最长15秒)...');
            
            let startTime = Date.now();
            let checkCount = 0;
            let maxChecks = 15;
            
            while (checkCount < maxChecks) {
                Sleep(1000);
                checkCount++;
                
                spotOrder = exchanges[0].GetOrder(spotOrderId);
                deliveryOrder = exchanges[1].GetOrder(deliveryOrderId);
                
                let spotStatus = spotOrder ? spotOrder.Status : -1;
                let deliveryStatus = deliveryOrder ? deliveryOrder.Status : -1;
                
                Log(`  第${checkCount}次检查: 现货状态=${spotStatus}, 期货状态=${deliveryStatus}`);
                
                if (spotStatus === 1 && deliveryStatus === 1) {
                    Log('✅ 两个订单都已成交!');
                    break;
                }
            }
            
            // 处理未成交情况
            let finalSpotStatus = spotOrder ? spotOrder.Status : -1;
            let finalDeliveryStatus = deliveryOrder ? deliveryOrder.Status : -1;
            
            if (finalSpotStatus === 1 && finalDeliveryStatus !== 1) {
                Log('⚠️ 现货已成交,期货未成交 - 强制平仓期货');
                if (finalDeliveryStatus === 0) exchanges[1].CancelOrder(deliveryOrderId);
                let forceDirection = record.direction === 'positive' ? 'closesell' : 'closebuy';
                let forceOrderId = exchanges[1].CreateOrder(record.deliverySymbol, forceDirection, -1, record.contractAmount);
                if (forceOrderId) {
                    Sleep(2000);
                    deliveryOrder = exchanges[1].GetOrder(forceOrderId);
                }
            }
            
            if (finalDeliveryStatus === 1 && finalSpotStatus !== 1) {
                Log('⚠️ 期货已成交,现货未成交 - 强制成交现货');
                if (finalSpotStatus === 0) exchanges[0].CancelOrder(spotOrderId);
                if (record.direction === 'positive') {
                    spotOrderId = exchanges[0].CreateOrder(record.spotSymbol, 'sell', -1, record.spotAmount);
                } else {
                    let currentPrice = DataLayer.getDepthMidPrice(exchanges[0], record.spotSymbol);
                    if (!currentPrice) currentPrice = verifySpotPrice;
                    let usdtAmount = record.spotAmount * currentPrice;
                    spotOrderId = exchanges[0].CreateOrder(record.spotSymbol, 'buy', -1, usdtAmount);
                }
                if (spotOrderId) {
                    Sleep(2000);
                    spotOrder = exchanges[0].GetOrder(spotOrderId);
                }
            }
            
            if (finalSpotStatus !== 1 && finalDeliveryStatus !== 1) {
                Log('❌ 两个订单都未成交');
                ExecutionLayer.addOpportunityLostCooldown(deliverySymbol, '平仓订单未成交');
                return false;
            }
            
            if (spotOrder && spotOrder.Status === 1) {
                DisplayLayer.printOrderDetails(exchanges[0], record.spotSymbol, spotOrder.Id, '平仓-现货订单');
            }
            
            if (deliveryOrder && deliveryOrder.Status === 1) {
                DisplayLayer.printOrderDetails(exchanges[1], record.deliverySymbol, deliveryOrder.Id, '平仓-期货订单');
            }
            
            // 成交价差验证和盈亏统计
            let closeSpotPrice = spotOrder.AvgPrice || verifySpotPrice;
            let closeDeliveryPrice = deliveryOrder.AvgPrice || verifyDeliveryPrice;
            let actualCloseSpread = closeDeliveryPrice - closeSpotPrice;
            
            let openSpotOrder = exchanges[0].GetOrder(record.spotOrderId);
            let openDeliveryOrder = exchanges[1].GetOrder(record.deliveryOrderId);
            
            let openSpotPrice = (openSpotOrder && openSpotOrder.AvgPrice) ? openSpotOrder.AvgPrice : record.openSpotPrice;
            let openDeliveryPrice = (openDeliveryOrder && openDeliveryOrder.AvgPrice) ? openDeliveryOrder.AvgPrice : record.openDeliveryPrice;
            let openSpread = openDeliveryPrice - openSpotPrice;
            
            let spotReturnRate = 0;
            let deliveryReturnRate = 0;
            
            if (record.direction === 'positive') {
                spotReturnRate = (closeSpotPrice - openSpotPrice) / openSpotPrice;
                deliveryReturnRate = (openDeliveryPrice - closeDeliveryPrice) / openDeliveryPrice;
            } else {
                spotReturnRate = (openSpotPrice - closeSpotPrice) / openSpotPrice;
                deliveryReturnRate = (closeDeliveryPrice - openDeliveryPrice) / openDeliveryPrice;
            }
            
            let totalReturnRate = spotReturnRate + deliveryReturnRate;
            let requiredUSD = openSpotPrice * record.spotAmount;
            let actualTotalPnl = totalReturnRate * requiredUSD;
            let actualSpotPnl = spotReturnRate * requiredUSD;
            let actualDeliveryPnl = deliveryReturnRate * requiredUSD;
            
            accumulatedProfit += actualTotalPnl;
            _G('accumulatedProfit', accumulatedProfit);
            
            Log('===================================');
            Log('💰 平仓盈亏统计');
            Log('===================================');
            Log('📊 开仓时价格:');
            Log('  现货价:', openSpotPrice.toFixed(2));
            Log('  期货价:', openDeliveryPrice.toFixed(2));
            Log('  价差:', openSpread.toFixed(4));
            Log('-----------------------------------');
            Log('📊 平仓时价格:');
            Log('  现货价:', closeSpotPrice.toFixed(2));
            Log('  期货价:', closeDeliveryPrice.toFixed(2));
            Log('  价差:', actualCloseSpread.toFixed(4));
            Log('-----------------------------------');
            Log('📈 收益分析:');
            Log('  现货收益率:', (spotReturnRate * 100).toFixed(4), '%', `| 盈亏: ${actualSpotPnl >= 0 ? '+' : ''}${actualSpotPnl.toFixed(4)} USDT`);
            Log('  合约收益率:', (deliveryReturnRate * 100).toFixed(4), '%', `| 盈亏: ${actualDeliveryPnl >= 0 ? '+' : ''}${actualDeliveryPnl.toFixed(4)} USDT`);
            Log('  总收益率:', (totalReturnRate * 100).toFixed(4), '%');
            Log('-----------------------------------');
            Log('💵 资金统计:');
            Log('  本次盈亏:', actualTotalPnl >= 0 ? `+${actualTotalPnl.toFixed(4)}` : actualTotalPnl.toFixed(4), 'USDT');
            Log('  累计盈亏:', accumulatedProfit >= 0 ? `+${accumulatedProfit.toFixed(4)}` : accumulatedProfit.toFixed(4), 'USDT');
            Log('===================================');
            
            closedTrades.push({
                coin: record.coin,
                deliverySymbol: deliverySymbol,
                direction: record.direction,
                deviation: record.deviation,
                openTime: record.openTime,
                closeTime: Date.now(),
                openSpotPrice: openSpotPrice,
                openDeliveryPrice: openDeliveryPrice,
                closeSpotPrice: closeSpotPrice,
                closeDeliveryPrice: closeDeliveryPrice,
                openSpread: openSpread,
                closeSpread: actualCloseSpread,
                targetSpreadLower: record.targetSpreadLower,
                targetSpreadUpper: record.targetSpreadUpper,
                targetAdjusted: record.targetAdjusted || false,
                spotAmount: record.spotAmount,
                contractAmount: record.contractAmount,
                spotReturnRate: spotReturnRate,
                deliveryReturnRate: deliveryReturnRate,
                totalReturnRate: totalReturnRate,
                actualPnl: actualTotalPnl,
                closeReason: closeReason.reason
            });
            
            _G('closedTrades', closedTrades);
            
            delete positionRecords[deliverySymbol];
            _G('positionRecords', positionRecords);
            
            DisplayLayer.updateProfit();
            
            Log('✅ 平仓完成!');
            Log('===================================');
            
            return true;
            
        } catch (e) {
            Log('❌ 平仓异常:', e.message);
            return false;
        }
    }
};

// ==================== 展示层 (DisplayLayer) ====================
const DisplayLayer = {
    /**
     * 打印订单详细信息
     */
    printOrderDetails: function(exchange, symbol, orderId, orderType) {
        Log('================================');
        Log(`📋 查询订单详情: ${orderType}`);
        Log(`  交易对: ${symbol}`);
        Log(`  订单ID: ${orderId}`);
        
        Sleep(1000);
        
        let order = exchange.GetOrder(orderId);
        
        if (!order) {
            Log('❌ 无法获取订单详情');
            return null;
        }
        
        let statusText = '';
        switch(order.Status) {
            case 0: statusText = '等待成交'; break;
            case 1: statusText = '已成交'; break;
            case 2: statusText = '已撤销'; break;
            case 3: statusText = '未知'; break;
            default: statusText = `未定义状态(${order.Status})`;
        }
        
        Log('✅ 订单详情:');
        Log(`  订单ID: ${order.Id}`);
        Log(`  交易对: ${order.Symbol || symbol}`);
        Log(`  订单类型: ${order.Type === 0 ? '买入' : order.Type === 1 ? '卖出' : '未知'}`);
        Log(`  订单价格: ${order.Price ? order.Price.toFixed(6) : '市价'}`);
        Log(`  平均成交价(AvgPrice): ${order.AvgPrice ? order.AvgPrice.toFixed(6) : 'N/A'} 💰`);
        Log(`  订单数量: ${order.Amount ? order.Amount.toFixed(6) : 'N/A'}`);
        Log(`  成交数量(DealAmount): ${order.DealAmount ? order.DealAmount.toFixed(6) : 'N/A'}`);
        Log(`  订单状态: ${statusText}`);
        Log('================================');
        
        return order;
    },

    /**
     * 更新收益显示
     */
    updateProfit: function() {
        try {
            LogProfit(accumulatedProfit, "&");
        } catch (e) {
            Log('❌ 更新收益异常:', e.message);
        }
    },

    /**
     * 创建系统状态表格
     */
    createSystemStatusTable: function(loopCount) {
        let realizedProfit = 0;
        let winCount = 0;
        closedTrades.forEach(t => {
            realizedProfit += t.actualPnl;
            if (t.actualPnl > 0) winCount++;
        });
        let winRate = closedTrades.length > 0 ? (winCount / closedTrades.length * 100) : 0;

        let floatingProfit = 0;
        let activePairsCount = Object.keys(positionRecords).length;
        let totalPairsCount = contractPairs.length;
        
        for (let symbol in positionRecords) {
            let record = positionRecords[symbol];
            let pair = contractPairs.find(p => p.deliverySymbol === symbol);
            if (record && pair) {
                let pnlInfo = SignalLayer.calculateUnrealizedPnL(record, pair);
                if (pnlInfo) floatingProfit += pnlInfo.totalPnl;
            }
        }

        let runningTimeStr = "-";
        if (strategyStartTime > 0) {
            let diff = Date.now() - strategyStartTime;
            let days = Math.floor(diff / (1000 * 60 * 60 * 24));
            let hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
            let mins = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
            runningTimeStr = `${days}d ${hours}h ${mins}m`;
        }

        let nextCheckMinutes = Math.floor((nextStationarityCheckTime - Date.now()) / 60000);
        let adfStatus = nextCheckMinutes <= 0 ? "⚠️ 检验中" : `⏳ ${nextCheckMinutes}分钟后`;

        const table = {
            type: "table",
            title: `📊 策略看板 v5.1 (增强回滚验证) | 运行: ${runningTimeStr} | 循环: ${loopCount}`,
            cols: ["指标", "数值"],
            rows: []
        };

        table.rows.push(["💰 累计盈亏", `${accumulatedProfit >= 0 ? '+' : ''}${accumulatedProfit.toFixed(2)} USDT`]);
        table.rows.push(["📈 已实现盈亏", `${realizedProfit >= 0 ? '+' : ''}${realizedProfit.toFixed(2)} USDT`]);
        table.rows.push(["⚖️ 未实现盈亏", `${floatingProfit >= 0 ? '+' : ''}${floatingProfit.toFixed(2)} USDT`]);
        table.rows.push(["📜 总交易笔数", `${closedTrades.length} 笔`]);
        table.rows.push(["🎯 交易胜率", winRate > 0 ? `${winRate.toFixed(1)}%` : "-"]);
        table.rows.push(["💼 持仓数/总对", `${activePairsCount} / ${totalPairsCount}`]);
        table.rows.push(["🔬 ADF检验", adfStatus]);

        return table;
    },

    /**
     * 创建持仓表格
     */
    createPositionTable: function() {
        const positionTable = {
            type: "table",
            title: "💼 当前持仓状态 (基于Depth实时价格)",
            cols: ["币种", "类型", "方向", "数量", "开仓价", "当前Depth价", "收益率", "实时盈亏", "持仓时长", "平仓条件"],
            rows: []
        };
        
        if (Object.keys(positionRecords).length === 0) {
            positionTable.rows.push([
                "📭", "空仓", "-", "-", "-", "-", "-", "-", "-", "等待开仓信号"
            ]);
            return positionTable;
        }
        
        for (let deliverySymbol in positionRecords) {
            let record = positionRecords[deliverySymbol];
            let coin = record.coin;
            let currentPair = contractPairs.find(p => p.deliverySymbol === deliverySymbol);
            if (!currentPair) continue;
            
            let deliveryPos = ExecutionLayer.getPositionBySymbol(deliverySymbol);
            if (!deliveryPos) continue;
            
            let holdHours = ((Date.now() - record.openTime) / (1000 * 60 * 60)).toFixed(1);
            let pnl = SignalLayer.calculateUnrealizedPnL(record, currentPair);
            
            let returnRateDisplay = "⏳";
            let pnlDisplay = "⏳";
            let closeConditionDisplay = "⏳";
            let currentPriceDisplay = "⏳";
            
            if (pnl) {
                currentPriceDisplay = `$${pnl.currentSpotPrice.toFixed(2)}`;
                
                if (pnl.totalPnlRate > 0) {
                    returnRateDisplay = `🟢 +${(pnl.totalPnlRate * 100).toFixed(3)}%`;
                    pnlDisplay = `🟢 +$${pnl.totalPnl.toFixed(2)}`;
                } else if (pnl.totalPnlRate < 0) {
                    returnRateDisplay = `🔴 ${(pnl.totalPnlRate * 100).toFixed(3)}%`;
                    pnlDisplay = `🔴 $${pnl.totalPnl.toFixed(2)}`;
                } else {
                    returnRateDisplay = `⚪ 0%`;
                    pnlDisplay = `⚪ $0`;
                }
                
                let closeCheck = SignalLayer.shouldClosePosition(deliverySymbol, currentPair);
                if (closeCheck.should) {
                    closeConditionDisplay = `🚨 ${closeCheck.reason}`;
                } else {
                    let currentSpread = pnl.currentDeliveryPrice - pnl.currentSpotPrice;
                    if (currentSpread >= record.targetSpreadLower && currentSpread <= record.targetSpreadUpper) {
                        closeConditionDisplay = `✅ 已进入目标区间`;
                    } else {
                        closeConditionDisplay = `📊 监控中`;
                    }
                }
            }
            
            let spotDirection = record.direction === 'positive' ? "📈 多" : "📉 空";
            positionTable.rows.push([
                `💎 ${coin}`,
                "现货",
                spotDirection,
                record.spotAmount.toFixed(4),
                `$${record.openSpotPrice.toFixed(2)}`,
                currentPriceDisplay,
                returnRateDisplay,
                pnlDisplay,
                `${holdHours}h`,
                closeConditionDisplay
            ]);
            
            let deliveryIsLong = deliveryPos.Type === PD_LONG || deliveryPos.Type === 0;
            let deliveryDirection = deliveryIsLong ? "📈 多" : "📉 空";
            let deliveryPriceDisplay = pnl ? `$${pnl.currentDeliveryPrice.toFixed(2)}` : "⏳";
            
            let targetDisplay = `目标: [${record.targetSpreadLower.toFixed(1)}, ${record.targetSpreadUpper.toFixed(1)}]`;
            if (record.targetAdjusted) {
                targetDisplay += ' 🔧';
            }
            
            positionTable.rows.push([
                "",
                `交割(×${record.ctVal})`,
                deliveryDirection,
                Math.abs(deliveryPos.Amount).toFixed(4),
                `$${record.openDeliveryPrice.toFixed(2)}`,
                deliveryPriceDisplay,
                "-",
                "-",
                "-",
                targetDisplay
            ]);
            
            positionTable.rows.push([
                "---", "---", "---", "---", "---", "---", "---", "---", "---", "---"
            ]);
        }
        
        if (positionTable.rows.length > 0 && positionTable.rows[positionTable.rows.length - 1][0] === "---") {
            positionTable.rows.pop();
        }
        return positionTable;
    },

    /**
     * 创建平稳性表格
     */
    createStationarityTable: function() {
        const table = {
            type: "table",
            title: "🔬 ADF平稳性检验(每小时)",
            cols: ["币种", "交割", "数据量", "ADF p值", "平稳", "失败次数", "可交易", "Z-Score", "信号", "状态"],
            rows: []
        };
        
        let validPairs = contractPairs.filter(p => p.daysToDelivery >= CONFIG.minDaysToDelivery);
        
        for (let pair of validPairs) {
            let stationarity = stationarityCache[pair.deliverySymbol];
            let zInfo = SignalLayer.calculateZScore(pair.deliverySymbol);
            
            let dataLengthDisplay = stationarity && stationarity.dataLength ? 
                `${stationarity.dataLength}` : "-";
            
            let adfDisplay = stationarity && stationarity.adf ? 
                stationarity.adf.pValue.toFixed(4) : "-";
            
            let stationaryDisplay = "";
            if (!stationarity) {
                stationaryDisplay = "⏳";
            } else if (stationarity.isStationary) {
                stationaryDisplay = "✅";
            } else {
                stationaryDisplay = "❌";
            }
            
            let failsDisplay = stationarity && stationarity.consecutiveFails !== undefined ? 
                `${stationarity.consecutiveFails}/${CONFIG.consecutiveFailThreshold}` : "-";
            
            let canTradeDisplay = "";
            if (!stationarity) {
                canTradeDisplay = "⏳";
            } else if (stationarity.canTrade) {
                canTradeDisplay = "✅ 是";
            } else {
                canTradeDisplay = "❌ 否";
            }
            
            let zDisplay = "-";
            let signalDisplay = "⏳";
            
            if (stationarity && stationarity.dataLength >= CONFIG.minHistoryForTest) {
                if (zInfo) {
                    zDisplay = zInfo.zScore.toFixed(2);
                    let absZ = Math.abs(zInfo.zScore);
                    
                    let hasPosition = positionRecords.hasOwnProperty(pair.deliverySymbol);
                    
                    if (hasPosition) {
                        signalDisplay = "💼 持仓";
                    } else if (stationarity.canTrade && absZ >= CONFIG.zScoreEntry) {
                        signalDisplay = "🚀 开仓";
                    } else if (stationarity.canTrade) {
                        signalDisplay = "👀 监控";
                    } else {
                        signalDisplay = "⚠️ 禁止";
                    }
                }
            }
            
            let statusDisplay = "✅";
            
            if (opportunityLostCooldowns[pair.deliverySymbol]) {
                let cooldownEnd = opportunityLostCooldowns[pair.deliverySymbol];
                let now = Date.now();
                if (now < cooldownEnd) {
                    let remainingSeconds = Math.ceil((cooldownEnd - now) / 1000);
                    statusDisplay = `⏸️ ${remainingSeconds}秒`;
                    signalDisplay = "⏸️ 1分冷却";
                }
            }
            
            if (pairCooldowns[pair.deliverySymbol]) {
                let cooldownEnd = pairCooldowns[pair.deliverySymbol];
                let now = Date.now();
                if (now < cooldownEnd) {
                    let remainingMinutes = Math.ceil((cooldownEnd - now) / 60000);
                    statusDisplay = `⏸️ ${remainingMinutes}分`;
                    signalDisplay = "⏸️ 10分冷却";
                }
            }
            
            table.rows.push([
                `💎 ${pair.coin}`,
                pair.deliveryTypeName,
                dataLengthDisplay,
                adfDisplay,
                stationaryDisplay,
                failsDisplay,
                canTradeDisplay,
                zDisplay,
                signalDisplay,
                statusDisplay
            ]);
        }
        
        return table;
    },

    /**
     * 创建历史交易表格
     */
    createClosedTradesTable: function() {
        const table = {
            type: "table",
            title: "📜 历史交易(最近10笔)",
            cols: ["币种", "方向", "偏离方", "开仓时间", "持仓", "现货%", "合约%", "总收益%", "盈亏", "原因"],
            rows: []
        };
        
        if (closedTrades.length === 0) {
            table.rows.push([
                "📭", "暂无历史交易", "-", "-", "-", "-", "-", "-", "-", "-"
            ]);
            return table;
        }
        
        let recentTrades = closedTrades.slice(-10).reverse();
        
        for (let trade of recentTrades) {
            let openDate = new Date(trade.openTime);
            let holdTime = ((trade.closeTime - trade.openTime) / (1000 * 60 * 60)).toFixed(1);
            
            let directionDisplay = trade.direction === 'positive' ? '正套' : '反套';
            if (trade.targetAdjusted) {
                directionDisplay += ' 🔧';
            }
            
            let deviationDisplay = "-";
            if (trade.deviation) {
                if (trade.deviation.isSpotDeviation) {
                    deviationDisplay = "现货";
                } else if (trade.deviation.isDeliveryDeviation) {
                    deviationDisplay = "期货";
                } else {
                    deviationDisplay = "双方";
                }
            }
            
            let spotRateDisplay = trade.spotReturnRate ? 
                `${(trade.spotReturnRate * 100).toFixed(3)}%` : '-';
            
            let deliveryRateDisplay = trade.deliveryReturnRate ? 
                `${(trade.deliveryReturnRate * 100).toFixed(3)}%` : '-';
            
            let totalRateDisplay = '';
            if (trade.totalReturnRate > 0) {
                totalRateDisplay = `🟢 +${(trade.totalReturnRate * 100).toFixed(3)}%`;
            } else if (trade.totalReturnRate < 0) {
                totalRateDisplay = `🔴 ${(trade.totalReturnRate * 100).toFixed(3)}%`;
            } else {
                totalRateDisplay = `⚪ 0%`;
            }
            
            let pnlDisplay = '';
            if (trade.actualPnl > 0) {
                pnlDisplay = `🟢 +$${trade.actualPnl.toFixed(2)}`;
            } else if (trade.actualPnl < 0) {
                pnlDisplay = `🔴 $${trade.actualPnl.toFixed(2)}`;
            } else {
                pnlDisplay = `⚪ $0`;
            }
            
            table.rows.push([
                `${trade.coin}`,
                directionDisplay,
                deviationDisplay,
                openDate.toLocaleString('zh-CN', {month:'2-digit', day:'2-digit', hour:'2-digit', minute:'2-digit'}),
                `${holdTime}h`,
                spotRateDisplay,
                deliveryRateDisplay,
                totalRateDisplay,
                pnlDisplay,
                trade.closeReason
            ]);
        }
        
        return table;
    },

    /**
     * 显示完整看板
     */
    displayDashboard: function(loopCount) {
        const systemStatusTable = DisplayLayer.createSystemStatusTable(loopCount);
        const stationarityTable = DisplayLayer.createStationarityTable();
        const positionTable = DisplayLayer.createPositionTable();
        const closedTradesTable = DisplayLayer.createClosedTradesTable();
        
        const dashboardDisplay = 
            '`' + JSON.stringify(systemStatusTable) + '`\n\n' +
            '`' + JSON.stringify(stationarityTable) + '`\n\n' +
            '`' + JSON.stringify(positionTable) + '`\n\n' +
            '`' + JSON.stringify(closedTradesTable) + '`';
        
        LogStatus(dashboardDisplay);
    }
};

// ==================== 主循环 ====================
function main() {
    LogProfitReset();
    LogReset();

    Log('🚀 启动现货-交割套利策略(重构版 v5.1)');
    Log('=== v5.1新增 ===');
    Log('  ✅ 回滚时使用Depth价格验证,确保回滚成功');
    Log('  ✅ 最多重试3次,完整的回滚验证机制');
    Log('=== 核心优化 ===');
    Log('  ✅ 去掉止盈,只保留止损(止损有二次确认)');
    Log('  ✅ 开仓前检查现货U余额(买入)和币余额(卖出)');
    Log('  ✅ 四层架构设计:数据层、信号层、执行层、展示层');
    Log('=== 保持功能 ===');
    Log('  ✅ 完全使用Depth盘口价格');
    Log('  ✅ 平仓前二次验证');
    Log('  ✅ 并发提交订单');
    Log('  ✅ 根据实际成交价差动态调整目标区间');
    Log('  ✅ 冷却期机制(10分钟+1分钟)');
    Log('=== 交易信号 ===');
    Log('  入场: |Z-Score| >=', CONFIG.zScoreEntry);
    Log('  出场: 价差回归目标区间');
    Log('  止损:', (CONFIG.stopLossRate * 100).toFixed(1), '%(有二次确认)');
    
    let savedRecords = _G('positionRecords');
    if (savedRecords) {
        positionRecords = savedRecords;
        Log('📥 恢复持仓记录:', Object.keys(positionRecords).length, '个');
    }
    
    DataLayer.loadHistoryData();
    
    if (!DataLayer.initContractPairs()) {
        Log('❌ 初始化合约配对失败');
        return;
    }
    
    if (!DataLayer.updatePrices()) {
        Log('❌ 初始化价格失败');
        return;
    }
    
    if (!DataLayer.initializeAccountRecords()) {
        Log('❌ 初始化账户记录失败');
        return;
    }
    
    strategyStartTime = Date.now();
    nextStationarityCheckTime = Date.now();
    
    let loopCount = 0;
    let lastSaveTime = Date.now();
    
    while (true) {
        loopCount++;
        
        if (!DataLayer.updatePrices()) {
            Log('⚠️ 更新价格失败');
            Sleep(CONFIG.checkInterval);
            continue;
        }
        
        SignalLayer.runStationarityChecks();
        
        // 检查现有持仓
        for (let deliverySymbol in positionRecords) {
            let record = positionRecords[deliverySymbol];
            let currentPair = contractPairs.find(p => p.deliverySymbol === deliverySymbol);
            if (!currentPair) continue;
            
            let deliveryPos = ExecutionLayer.getPositionBySymbol(deliverySymbol);
            if (!deliveryPos) {
                Log(`⚠️ ${deliverySymbol} 持仓不完整,清理记录`);
                delete positionRecords[deliverySymbol];
                _G('positionRecords', positionRecords);
                continue;
            }
            
            let closeCheck = SignalLayer.shouldClosePosition(deliverySymbol, currentPair);
            if (closeCheck.should) {
                ExecutionLayer.closePosition(deliverySymbol, currentPair, closeCheck);
            }
        }
        
        // 寻找开仓机会
        for (let pair of contractPairs) {
            if (pair.daysToDelivery < CONFIG.minDaysToDelivery) continue;
            if (ExecutionLayer.checkCooldown(pair.deliverySymbol, pair.coin)) continue;
            if (ExecutionLayer.checkOpportunityLostCooldown(pair.deliverySymbol)) continue;
            
            let hasPosition = positionRecords.hasOwnProperty(pair.deliverySymbol);
            if (hasPosition) continue;
            
            let openCheck = SignalLayer.shouldOpenPosition(pair);
            if (openCheck.should) {
                ExecutionLayer.openPosition(pair, openCheck);
            }
        }
        
        if (loopCount % 10 === 0) {
            DisplayLayer.updateProfit();
            DisplayLayer.displayDashboard(loopCount);
        }
        
        if (Date.now() - lastSaveTime > 3600000) {
            DataLayer.saveHistoryData();
            lastSaveTime = Date.now();
        }
        
        Sleep(CONFIG.checkInterval);
    }
}

function onexit(){
    Log('清理缓存数据');
    DataLayer.saveHistoryData();
    Log(_G(null));
}