资源加载中... loading...

数字货币中的Lead-Lag套利介绍(3)

Author: 小草, Created: 2024-12-24 15:43:36, Updated: 2024-12-25 14:30:29

在上一篇文章中,我们介绍了跨交易所的“搬砖”套利。这一次,我们将深入探讨如何将Lead-Lag效应应用于高频交易,高频交易需要在极短时间内捕捉微小的价格差异并迅速获利。Lead-Lag效应为交易者提供了预测性信息,帮助他们判断价格的短期走势,从而在不同交易所之间实现套利。

以下是对公开代码的简化,并转化为基于FMZ API。这个原策略的代码原理很简单,曾经也非常赚钱,当前不可用,仅供参考。


Lead-Lag高频策略原理

所谓“Lead-Lag”,可以理解为某些交易所的价格(或是某些指标)会在整体市场变化中更“领先”(Lead),而其他交易所或其他指标会相对“滞后”(Lag)。在本策略中,“价格_1、价格_2、价格_3”分别代表了不同交易所的行情,它们是主流的交易所,由于对对市场消息更敏感,或其交易深度、参与者类型不同,一旦有大额买单或卖单,就会使这些交易所的价格先一步波动。实际交易的交易所由于撮合机制、交易群体等因素,价格波动会稍微滞后。此时就出现了“某所领先、某所滞后”的状态。

多交易所订单簿抓取

策略几乎同步地获取不同交易所的订单簿数据,比如买一价、卖一价、挂单量等。然后对不同交易所的中间价(即买一卖一的平均值)进行比较,以此推断市场动态。

趋势信号判断

策略主要关注三个外部交易所(okex、binance、huobipro)的价格变化量:

这里,每一个 trendX 都是由“当前价格”与“过去价格”之差超过一定阈值(level * price_increment)来决定的。从三个交易所得到的“上涨/下跌”信号相加之后,如果总体 trend > 0,说明行情整体趋涨,策略就去买入;如果 trend < 0,则说明行情整体趋跌,策略就去卖出。

单向下单与风控

策略每次只在趋势确认后才去买或卖,并且在每一次下单前都会取消先前的订单(即避免意外的挂单导致风险积累)。同时,脚本里也设定了加杠杆、批量运行、风控监控等模块,说明在实际实盘时用的是多账号、多币对同时跑,从而扩充了策略的“交易频度”和“资金利用效率”。

另外该策略是高频策略,不用关注每一笔订单的盈亏,也不用止损,只要大概率能盈利就可继续。


FMZ策略实现

参数设置

// 超参设置
const SYMBOL = "BTC_USDT"; // 交易对
const PRICE_INCREMENT = 0.1; // 价格增量
const LEVEL = 10; // 趋势判断的灵敏度
const RATIO = 10; // 下单价格调整比例
const INTERVAL = 200; // 时间间隔(毫秒)
const S_AMOUNT = 0.02; // 默认交易量
const MIN_AMOUNT = 0.005; // 最小交易量

// 初始状态
let buyOrders = [];
let sellOrders = [];
let previousPrices = [0, 0, 0]; // 存储之前的价格
let loop = 0;

核心逻辑:获取数据与判断趋势

// 获取订单簿数据
function fetchOrderBooks() {
    let orderBooks = [];
    let tasks = [];

    // 启动所有交易所的异步获取订单簿任务
    for (let i = 0; i < exchanges.length; i++) {
        // 假设每个交易所对象都可以调用Go方法
        let task = exchanges[i].Go("GetDepth");
        tasks.push({ index: i, task: task });
    }

    // 等待所有任务完成并收集结果
    for (let i = 0; i < tasks.length; i++) {
        let { index, task } = tasks[i];
        try {
            // 等待异步任务返回结果
            let depth = task.wait(1000);

            // 检查返回的数据是否有效
            if (!depth || !depth.Bids || !depth.Asks) {
                throw new Error("返回的订单簿数据无效");
            }

            // 将有效的订单簿数据添加到结果数组
            orderBooks[index] = depth;
        } catch (error) {
            // 记录错误日志
            Log(`获取交易所${index}订单簿失败: ${error.message}`);

            // 添加默认的订单簿数据以避免崩溃
            orderBooks[index] = {
                Bids: [[0, 0]],
                Asks: [[0, 0]]
            };
        }
    }

    return orderBooks;
}


// 判断趋势
function calculateTrend(orderBooks) {
    let trends = [];
    for (let i = 0; i < orderBooks.length; i++) {
        const midPrice = (orderBooks[i].Bids[0][0] + orderBooks[i].Asks[0][0]) / 2;
        if (midPrice > previousPrices[i] + LEVEL * PRICE_INCREMENT) {
            trends.push(1); // 上升趋势
        } else if (midPrice < previousPrices[i] - LEVEL * PRICE_INCREMENT) {
            trends.push(-1); // 下降趋势
        } else {
            trends.push(0); // 无显著趋势
        }
        previousPrices[i] = midPrice; // 更新价格记录
    }
    return trends.reduce((a, b) => a + b, 0); // 返回总体趋势
}

下单与取消订单

// 取消所有挂单
function cancelOrders(orders) {
    for (let orderId of orders) {
        try {
            exchanges[0].CancelOrder(orderId); // 默认使用主交易所
            Log(`取消订单: ${orderId}`);
        } catch (error) {
            Log(`取消订单失败: ${error.message}`);
        }
    }
}

// 创建买单
function createBuyOrder(price, amount) {
    try {
        const orderId = exchanges[0].Buy(price, amount);
        buyOrders.push(orderId);
        Log(`创建买单: 价格 ${price}, 数量 ${amount}`);
    } catch (error) {
        Log(`创建买单失败: ${error.message}`);
    }
}

// 创建卖单
function createSellOrder(price, amount) {
    try {
        const orderId = exchanges[0].Sell(price, amount);
        sellOrders.push(orderId);
        Log(`创建卖单: 价格 ${price}, 数量 ${amount}`);
    } catch (error) {
        Log(`创建卖单失败: ${error.message}`);
    }
}

策略主逻辑

function main() {
    while (true) {
        try {
            // 获取订单簿数据
            const orderBooks = fetchOrderBooks();

            // 计算趋势
            const trend = calculateTrend(orderBooks);
            Log(`当前趋势: ${trend}`);

            // 取消挂单
            cancelOrders(buyOrders);
            cancelOrders(sellOrders);
            buyOrders = [];
            sellOrders = [];

            // 根据趋势下单
            if (trend > 0 && loop > 0) {
                const price = _N(orderBooks[0].Bids[0][0] + RATIO * PRICE_INCREMENT, 2);
                const amount = _N(Math.max(S_AMOUNT, MIN_AMOUNT), 4);
                createBuyOrder(price, amount);
            } else if (trend < 0 && loop > 0) {
                const price = _N(orderBooks[0].Asks[0][0] - RATIO * PRICE_INCREMENT, 2);
                const amount = _N(Math.max(S_AMOUNT, MIN_AMOUNT), 4);
                createSellOrder(price, amount);
            }

            // 循环计数与间隔
            loop++;
            Sleep(INTERVAL);

        } catch (error) {
            Log(`主逻辑错误: ${error.message}`);
        }
    }
}

策略失效原因分析

市场变得有效

当越来越多的量化或者高频策略参与进来,发现同样的Lead-Lag关系,大量资金会把这种价差迅速抹平。市场变得越来越“同步”,策略就很难再从微小价差里“无风险”套利或短期套利。

交易所限制或手续费变化

随着不同交易所手续费结构的变化,一旦手续成本超出了套利收益,高频交易策略的盈利能力就大打折扣。或者交易所加速撮合速度、限频限量、降低延迟,也会让本来依靠延迟不一致的策略失效。

流动性衰减与滑点

当市场成交量不足,高频策略往往会遭遇更严重的滑点;或者大单子会快速推动价格,导致本来预期的“买低卖高”反而被自己的单子影响,收益下滑。

市场波动环境改变

一些策略在“高波动”或“特定周期”下非常好用,当市场平淡或波动率下降、杠杆降低,策略就失去了适宜的环境,甚至可能会频繁亏损。


总结

这个高频交易策略的关键点,就在于对多交易所价格的抓取以及“趋势合成”判断。它曾经基于Lead-Lag原理实现了超高频、快速进出的交易方式:观察哪家交易所的价格先动,然后带动其他交易所价格跟随,从中捕捉瞬时差价或短期趋势。然而,正如作者所言,市场环境、策略同质化、手续费与限频的变化,让这种依赖“先动后动”价差的策略逐渐变得没那么好用,甚至失去盈利能力。对于想要再挖掘此类Lead-Lag策略的人,需要结合最新的市场结构(流动性、手续费规则、算法撮合速度)去优化交易模块,同时注重风控管理,才能在变化的市场环境中保持持续竞争力。


More