avatar of 发明者量化-小小梦 发明者量化-小小梦
focar em Mensagem privada
4
focar em
1319
Seguidores

Reinício sem custos de estratégias antigas: FMZ + Lighter DEX + IA na prática

Criado em: 2026-01-22 09:30:47, atualizado em: 2026-01-22 18:12:51
comments   8
hits   582

[TOC]

Reinício sem custos de estratégias antigas: FMZ + Lighter DEX + IA na prática

Prefácio

Recentemente, a plataforma quantitativa FMZ foi oficialmente integrada.Lighter DEXPara ser sincero, não dei muita atenção a essa notícia quando a vi pela primeira vez — afinal, existem inúmeras DEXs no mercado. Mas, depois de me informar melhor, uma característica me chamou a atenção: taxas de transação zero.

Sim, você leu certo. A Lighter DEX oferece zero taxas de comissão para traders regulares. Isso me lembrou imediatamente de algo: será que eu finalmente poderia retomar aquelas estratégias que eu havia “arquivado” anos atrás por causa dos custos de comissão? Então, abri a FMZ…Praça da EstratégiaEm busca de estratégias daqueles “tempos antigos”…

1. Lighter

Não vou entrar em muitos detalhes sobre essa DEX recém-adicionada; os interessados ​​podem pesquisar para saber mais. Atualmente, a experiência do usuário é bastante boa. Em termos de experiência do usuário, a Lighter oferece desempenho comparável ao de exchanges centralizadas, mantendo a transparência descentralizada, e permanece relativamente estável mesmo com acesso frequente à API.

Resumo dos dados

Segue uma compilação de algumas informações:

Configuração

A seguir, apresentarei brevemente como configurar o FMZ.LighterAdicione as informações de configuração da chave de API do Lighter na página de troca da plataforma FMZ.

Reinício sem custos de estratégias antigas: FMZ + Lighter DEX + IA na prática

É necessário configurar três coisas:

  • chave privada da API de assinatura Esta não é a chave privada da carteira. Esta chave privada de assinatura é uma chave privada usada para realizar ordens e transações, criada após o login no Lighter e a conexão da sua carteira em https://app.lighter.xyz.

Reinício sem custos de estratégias antigas: FMZ + Lighter DEX + IA na prática

  • Se você estiver acessando o ambiente de teste do Lighter, a chave criada será a chave do ambiente de teste, que não será detalhada aqui.
  • Ao criar uma chave privada de assinatura, você precisa especificar um índice. Os bits de 0 a 2 são reservados, e você pode especificar a partir de 3.
  • Todas essas etapas de login e criação exigem a assinatura de uma carteira, e eu usei a Binance Wallet e tive uma boa experiência.

Criadochave privada de assinaturaA configuração pode ser feita na caixa de edição de controle correspondente na página Adicionar Exchange do FMZ.

  • Nota importante: Você precisa baixar a versão mais recente do programa de custódia para dar suporte à bolsa de contratos futuros Lighter.

  • Índice da API Insira o índice correspondente à chave privada de assinatura.

  • Índice de contas Os índices de contas podem ser obtidos através da API do Lighter:

    • Interface da API:https://mainnet.zklighter.elliot.ai/api/v1/account?by=l1_address&value={钱包地址} Por exemplo, acesse o endereço diretamente no navegador:https://mainnet.zklighter.elliot.ai/api/v1/account?by=l1_address&value=0x123xxxx0x123xxxxEste é apenas um endereço de exemplo; substitua este conteúdo ao utilizá-lo na prática. Dados retornados:
    {
      "code": 200,
      "total": 1,
      "accounts": [
        {
          "code": 0,
          "account_type": 0,
          "index": 1234567,
          "l1_address": "0x123xxxx",
    

    em"index": 1234567Esse é o índice da sua conta.

    • O processo inicial de criação só começará quando os ativos (como USDC) forem transferidos.Lighterconta

    • Note que a interface obtida usando o endpoint da rede principal recupera o índice de contas da rede principal, enquanto a interface obtida usando o endpoint da rede de testes recupera o índice de contas da rede de testes.

Por que precisamos preencher este índice de contas? PorqueLighterExiste um sistema de subcontas que distingue diferentes contas com base no índice da conta. Se precisar usar uma subconta, você pode configurar o índice da conta da subconta aqui (o índice da conta da subconta aparecerá nos dados JSON retornados pelo link de consulta acima).

2. Estratégias antigas no FMZ

Taxas zero: uma mudança radical.

Essa é a funcionalidade que mais me empolga. A Lighter oferece uma política de taxa zero para traders comuns.

  • O que significa taxa de transação zero?

As estratégias de negociação de alta frequência não têm mais seus lucros “consumidos” por taxas de transação. A estratégia de malha permite definir um espaçamento de malha mais denso. O ponto de equilíbrio para estratégias de arbitragem foi significativamente reduzido. Aquelas estratégias que eram “teoricamente viáveis, mas inviabilizadas na prática pelas taxas de transação” finalmente encontraram uma forma de serem utilizadas.

Desvendando uma estratégia ancestral: o fascínio das taxas de transação zero.

Biblioteca de Estratégia Arqueologia

Com a pergunta em mente, “Quais estratégias podem ser revitalizadas sem taxas de transação?”, comecei a pesquisar na biblioteca de estratégias e na comunidade da FMZ. Logo, uma estratégia familiar me chamou a atenção:

https://www.fmz.com/digest-topic/1211

Essa estratégia é simples e direta, mas em um ambiente com taxas de transação, quase sempre resulta em prejuízo. No entanto, no ambiente sem taxas de transação do Lighter, vale a pena tentar.

Então, eis a questão:

Eis o problema: o código está muito desatualizado. Analisando a estratégia, o código é simples e baseado em força bruta, quase sem conteúdo de interface do usuário e carente de alguns recursos de acessibilidade. Aqui estão alguns exemplos do que está faltando:

  • Algumas interfaces de API estão desatualizadas.
  • Falta-lhe módulos modernos de controlo de riscos.
  • Faltam informações.
  • Não há estatísticas de receita.

Refatorar esse código manualmente? Para ser sincero, é um pouco assustador. No entanto, encontrei uma solução “preguiçosa”: deixar a IA fazer a refatoração para mim.

3. Estratégia de Reestruturação

Primeiramente, vamos estabelecer uma precaução: este artigo é apenas uma tentativa exploratória de reconstruir uma estratégia usando IA em uma exchange DEX emergente, e não garantimos a rentabilidade da estratégia reconstruída. Então, vamos começar a reconstruir essa estratégia antiga usando Claude. Não quero escrever o código do zero; meus requisitos são:

  • Mantenha a lógica central da estratégia original.
  • Adaptado às especificações mais recentes da API do FMZ.
  • Adicionar os módulos necessários de controle de risco e registro de atividades.
  • As informações apresentadas são relativamente completas e claras.
  • Otimize a lógica do código adequadamente.

Forneça o código original à IA.

Copiei o código da estratégia original e o enviei, juntamente com meus requisitos, para a IA. Após várias rodadas de diálogo e ajustes, a IA gerou o código refatorado para mim:

bash: while :; do cat PROMPT.md | claude-code ; done
) (Pensamentos a serem aprendidos)
/*
高频做市策略 - FMZ期货版(带仓位矫正)
策略参数:
- sleeptime: 休眠时间(毫秒) - 默认3500
- floatamountbuy: 买单深度阈值 - 默认20
- floatamountsell: 卖单深度阈值 - 默认20
- diffprice: 最小套利差价 - 默认50
- baseAmount: 基础下单量 - 默认0.1
- maxPosition: 最大单边持仓量 - 默认10
- stopLossRatio: 止损比例 - 默认0.9 (90%)
- closeOnExit: 退出时清仓 - 默认false
*/

// 全局变量
var pricePrecision = 2;
var amountPrecision = 3;
var tickSize = 0.01;
var minQty = 0.001;
var symbol = "ETH_USDT.swap";

// 统计信息
var stats = {
    startTime: 0,
    cycleCount: 0,
    orderCount: 0,
    cancelCount: 0,
    initialEquity: 0,
    currentEquity: 0,
    maxEquity: 0,
    maxDrawdown: 0,
    isStopLoss: false,
    lastLogCleanTime: 0,
    lastEmergencyTime: 0
};

// 日志清理配置
var LOG_CLEAN_INTERVAL = 60 * 60 * 1000;
var LOG_RESERVE_COUNT = 10000;
var EMERGENCY_COOLDOWN = 5000;

// ==================== 精度工具函数 ====================

/**
 * 从数值推断精度(小数位数)
 * 例如: 0.005 -> 3, 0.0001 -> 4, 0.1 -> 1, 1 -> 0
 */
function GetPrecisionFromValue(value) {
    if (!value || value >= 1) return 0;
    
    var str = value.toString();
    
    // 处理科学计数法 (如 1e-4)
    if (str.indexOf('e') !== -1) {
        var match = str.match(/e-(\d+)/);
        return match ? parseInt(match[1]) : 0;
    }
    
    // 处理普通小数
    if (str.indexOf('.') === -1) return 0;
    
    return str.split('.')[1].length;
}

/**
 * 规范化下单量
 * 1. 按精度取整
 * 2. 确保是 minQty 的整数倍
 * 3. 不小于 minQty
 */
function NormalizeAmount(amount) {
    if (amount <= 0) return 0;
    
    // 按精度取整
    var normalized = _N(amount, amountPrecision);
    
    // 确保是 minQty 的整数倍
    if (minQty > 0) {
        normalized = Math.floor(normalized / minQty) * minQty;
        normalized = _N(normalized, amountPrecision);
    }
    
    // 检查最小下单量
    if (normalized < minQty) {
        return 0;
    }
    
    return normalized;
}

/**
 * 规范化价格
 */
function NormalizePrice(price) {
    if (tickSize > 0) {
        price = Math.round(price / tickSize) * tickSize;
    }
    return _N(price, pricePrecision);
}

// 取消全部订单
function CancelPendingOrders() {
    var orders = _C(exchange.GetOrders, symbol);
    var count = 0;
    for (var j = 0; j < orders.length; j++) {
        exchange.CancelOrder(orders[j].Id, orders[j]);
        count++;
    }
    if (count > 0) {
        stats.cancelCount += count;
    }
    return count;
}

// 计算将要下单的价格
function GetPrice(Type, depth) {
    var amountBids = 0;
    var amountAsks = 0;
    
    if (Type == "Buy") {
        for (var i = 0; i < 20 && i < depth.Bids.length; i++) {
            amountBids += depth.Bids[i].Amount;
            if (amountBids > floatamountbuy) {
                return NormalizePrice(depth.Bids[i].Price + tickSize);
            }
        }
    }
    
    if (Type == "Sell") {
        for (var j = 0; j < 20 && j < depth.Asks.length; j++) {
            amountAsks += depth.Asks[j].Amount;
            if (amountAsks > floatamountsell) {
                return NormalizePrice(depth.Asks[j].Price - tickSize);
            }
        }
    }
    
    return NormalizePrice(depth.Asks[0].Price);
}

// 获取持仓信息
function GetPosition() {
    var positions = _C(exchange.GetPositions, symbol);
    var pos = {
        long: { amount: 0, price: 0, profit: 0 },
        short: { amount: 0, price: 0, profit: 0 }
    };
    
    for (var i = 0; i < positions.length; i++) {
        var p = positions[i];
        if (p.Type === PD_LONG || p.Type === 0) {
            pos.long.amount = p.Amount;
            pos.long.price = p.Price;
            pos.long.profit = p.Profit || 0;
        } else {
            pos.short.amount = p.Amount;
            pos.short.price = p.Price;
            pos.short.profit = p.Profit || 0;
        }
    }
    return pos;
}

// 计算账户权益
function GetEquity(account, pos) {
    var equity = account.Balance + account.FrozenBalance + pos.long.profit + pos.short.profit;
    return equity;
}

// 检查资金是否足够下单
function CheckFunds(account, price, amount, leverage) {
    leverage = leverage || 10;
    var requiredMargin = (price * amount) / leverage;
    var availableBalance = account.Balance;
    var safeBalance = availableBalance * 0.9;
    return safeBalance >= requiredMargin;
}

// ==================== 仓位矫正机制 ====================

/**
 * 计算动态开仓量(负反馈机制)
 */
function CalcOpenAmount(pos, direction) {
    var currentPos = (direction === "long") ? pos.long.amount : pos.short.amount;
    var posRatio = currentPos / maxPosition;
    
    if (currentPos >= maxPosition) {
        return 0;
    }
    
    var amount = baseAmount;
    if (posRatio > 0.8) {
        amount = baseAmount * 0.2;
    } else if (posRatio > 0.6) {
        amount = baseAmount * 0.4;
    } else if (posRatio > 0.4) {
        amount = baseAmount * 0.6;
    } else if (posRatio > 0.2) {
        amount = baseAmount * 0.8;
    }
    
    var netPos = pos.long.amount - pos.short.amount;
    if (direction === "long" && netPos > maxPosition * 0.3) {
        amount = amount * 0.5;
    } else if (direction === "short" && netPos < -maxPosition * 0.3) {
        amount = amount * 0.5;
    }
    
    return NormalizeAmount(amount);
}

/**
 * 计算动态平仓量
 */
function CalcCloseAmount(pos, direction) {
    var currentPos = (direction === "long") ? pos.long.amount : pos.short.amount;
    if (currentPos <= 0) return 0;
    
    var posRatio = currentPos / maxPosition;
    var amount = baseAmount;
    
    if (posRatio > 1.0) {
        amount = currentPos;
    } else if (posRatio > 0.8) {
        amount = baseAmount * 3.0;
    } else if (posRatio > 0.6) {
        amount = baseAmount * 2.0;
    } else if (posRatio > 0.4) {
        amount = baseAmount * 1.5;
    }
    
    amount = Math.min(amount, currentPos);
    
    return NormalizeAmount(amount);
}

/**
 * 计算平仓价格(仓位重时更激进)
 */
function CalcClosePrice(pos, depth, direction) {
    var currentPos = (direction === "long") ? pos.long.amount : pos.short.amount;
    var posRatio = currentPos / maxPosition;
    
    if (direction === "long") {
        if (posRatio > 1.0) {
            return NormalizePrice(depth.Bids[0].Price - tickSize * 3);
        } else if (posRatio > 0.8) {
            return NormalizePrice(depth.Bids[0].Price);
        } else if (posRatio > 0.5) {
            var midPrice = (depth.Bids[0].Price + depth.Asks[0].Price) / 2;
            return NormalizePrice(midPrice);
        }
        return NormalizePrice(depth.Asks[0].Price - tickSize);
    } else {
        if (posRatio > 1.0) {
            return NormalizePrice(depth.Asks[0].Price + tickSize * 3);
        } else if (posRatio > 0.8) {
            return NormalizePrice(depth.Asks[0].Price);
        } else if (posRatio > 0.5) {
            var midPrice = (depth.Bids[0].Price + depth.Asks[0].Price) / 2;
            return NormalizePrice(midPrice);
        }
        return NormalizePrice(depth.Bids[0].Price + tickSize);
    }
}

/**
 * 紧急减仓
 */
function EmergencyReduce(pos, depth) {
    var now = new Date().getTime();
    
    if (now - stats.lastEmergencyTime < EMERGENCY_COOLDOWN) {
        return false;
    }
    
    var needReduce = false;
    
    if (pos.long.amount > maxPosition * 1.2) {
        var reduceAmount = NormalizeAmount(pos.long.amount - maxPosition);
        if (reduceAmount > 0) {
            Log("⚠️ 多头严重超标 (" + pos.long.amount + "/" + maxPosition + "),市价减仓: " + reduceAmount, "#FF0000");
            var orderId = exchange.CreateOrder(symbol, "closebuy", -1, reduceAmount);
            if (orderId) {
                stats.orderCount++;
                stats.lastEmergencyTime = now;
            }
            needReduce = true;
        }
    }
    
    if (pos.short.amount > maxPosition * 1.2) {
        var reduceAmount = NormalizeAmount(pos.short.amount - maxPosition);
        if (reduceAmount > 0) {
            Log("⚠️ 空头严重超标 (" + pos.short.amount + "/" + maxPosition + "),市价减仓: " + reduceAmount, "#FF0000");
            var orderId = exchange.CreateOrder(symbol, "closesell", -1, reduceAmount);
            if (orderId) {
                stats.orderCount++;
                stats.lastEmergencyTime = now;
            }
            needReduce = true;
        }
    }
    
    if (needReduce) {
        Sleep(1000);
    }
    
    return needReduce;
}

function IsPositionOverload(pos) {
    return pos.long.amount > maxPosition || pos.short.amount > maxPosition;
}

// ==================== 日志清理 ====================

function CleanLogs() {
    var now = new Date().getTime();
    if (now - stats.lastLogCleanTime > LOG_CLEAN_INTERVAL) {
        LogReset(LOG_RESERVE_COUNT);
        stats.lastLogCleanTime = now;
        Log("日志已清理,保留最近 " + LOG_RESERVE_COUNT + " 条", "#0000FF");
    }
}

// ==================== 清仓相关 ====================

function CloseAllPositions(reason) {
    reason = reason || "手动触发";
    Log("========== 触发清仓 [" + reason + "] ==========", "#FF0000");
    
    CancelPendingOrders();
    Sleep(500);
    
    var pos = GetPosition();
    
    if (pos.long.amount > 0) {
        var orderId = exchange.CreateOrder(symbol, "closebuy", -1, pos.long.amount);
        if (orderId) {
            Log("市价平多: " + pos.long.amount, "#FF0000");
        }
    }
    
    if (pos.short.amount > 0) {
        var orderId = exchange.CreateOrder(symbol, "closesell", -1, pos.short.amount);
        if (orderId) {
            Log("市价平空: " + pos.short.amount, "#FF0000");
        }
    }
    
    Sleep(2000);
    
    var finalPos = GetPosition();
    if (finalPos.long.amount > 0 || finalPos.short.amount > 0) {
        Log("⚠️ 警告:仍有未平仓位!多头: " + finalPos.long.amount + ", 空头: " + finalPos.short.amount, "#FF0000");
        if (finalPos.long.amount > 0) {
            exchange.CreateOrder(symbol, "closebuy", -1, finalPos.long.amount);
        }
        if (finalPos.short.amount > 0) {
            exchange.CreateOrder(symbol, "closesell", -1, finalPos.short.amount);
        }
        Sleep(1000);
    } else {
        Log("✅ 所有仓位已清空", "#00FF00");
    }
    
    Log("========== 清仓完成 ==========", "#FF0000");
}

function CheckStopLoss(equity) {
    if (stats.isStopLoss) {
        return true;
    }
    
    var threshold = stats.initialEquity * stopLossRatio;
    
    if (equity < threshold) {
        stats.isStopLoss = true;
        var lossPercent = ((stats.initialEquity - equity) / stats.initialEquity * 100).toFixed(2);
        Log("⚠️ 触发止损! 当前权益: " + _N(equity, 4) + " USDT, 损失: " + lossPercent + "%", "#FF0000");
        return true;
    }
    
    return false;
}

function UpdateProfitChart(equity) {
    var profit = equity - stats.initialEquity;
    
    if (equity > stats.maxEquity) {
        stats.maxEquity = equity;
    }
    var drawdown = (stats.maxEquity - equity) / stats.maxEquity * 100;
    if (drawdown > stats.maxDrawdown) {
        stats.maxDrawdown = drawdown;
    }
    
    LogProfit(_N(profit, 4), "&");
}

function UpdateStatus(account, pos, depth, buyPrice, sellPrice, equity) {
    var runTime = (new Date().getTime() - stats.startTime) / 1000 / 60;
    var hours = Math.floor(runTime / 60);
    var mins = Math.floor(runTime % 60);
    
    var spread = sellPrice - buyPrice;
    var marketSpread = depth.Asks[0].Price - depth.Bids[0].Price;
    
    var profit = equity - stats.initialEquity;
    var profitPercent = (profit / stats.initialEquity * 100).toFixed(2);
    var drawdown = stats.maxEquity > 0 ? ((stats.maxEquity - equity) / stats.maxEquity * 100).toFixed(2) : 0;
    
    var longRatio = (pos.long.amount / maxPosition * 100).toFixed(1);
    var shortRatio = (pos.short.amount / maxPosition * 100).toFixed(1);
    var netPos = _N(pos.long.amount - pos.short.amount, amountPrecision);
    
    var table1 = {
        type: "table",
        title: "💰 账户信息",
        cols: ["项目", "数值"],
        rows: [
            ["可用余额", _N(account.Balance, 4) + " USDT"],
            ["冻结余额", _N(account.FrozenBalance, 4) + " USDT"],
            ["当前权益", _N(equity, 4) + " USDT"],
            ["初始权益", _N(stats.initialEquity, 4) + " USDT"],
            ["最高权益", _N(stats.maxEquity, 4) + " USDT"]
        ]
    };
    
    var table2 = {
        type: "table",
        title: "📈 收益统计",
        cols: ["项目", "数值"],
        rows: [
            ["累计收益", _N(profit, 4) + " USDT"],
            ["收益率", profitPercent + " %"],
            ["最大回撤", drawdown + " %"],
            ["止损阈值", (stopLossRatio * 100) + " %"],
            ["止损状态", stats.isStopLoss ? "⚠️ 已触发" : "✅ 正常"]
        ]
    };
    
    var longStatus, shortStatus;
    if (longRatio > 120) {
        longStatus = "🔴 紧急减仓";
    } else if (longRatio > 100) {
        longStatus = "🟠 超标";
    } else if (longRatio > 80) {
        longStatus = "🟡 控量";
    } else {
        longStatus = "🟢 正常";
    }
    
    if (shortRatio > 120) {
        shortStatus = "🔴 紧急减仓";
    } else if (shortRatio > 100) {
        shortStatus = "🟠 超标";
    } else if (shortRatio > 80) {
        shortStatus = "🟡 控量";
    } else {
        shortStatus = "🟢 正常";
    }
    
    var table3 = {
        type: "table",
        title: "📊 持仓信息(仓位矫正)",
        cols: ["方向", "数量", "上限", "使用率", "状态", "浮盈"],
        rows: [
            ["多头", pos.long.amount, maxPosition, longRatio + "%", longStatus, _N(pos.long.profit, 4)],
            ["空头", pos.short.amount, maxPosition, shortRatio + "%", shortStatus, _N(pos.short.profit, 4)],
            ["净仓", netPos, "-", "-", netPos > 0 ? "偏多" : (netPos < 0 ? "偏空" : "均衡"), "-"]
        ]
    };
    
    var table4 = {
        type: "table",
        title: "🎯 做市信息",
        cols: ["项目", "数值"],
        rows: [
            ["买一价", _N(depth.Bids[0].Price, pricePrecision)],
            ["卖一价", _N(depth.Asks[0].Price, pricePrecision)],
            ["盘口价差", _N(marketSpread, pricePrecision)],
            ["挂单买价", _N(buyPrice, pricePrecision)],
            ["挂单卖价", _N(sellPrice, pricePrecision)],
            ["做市价差", _N(spread, pricePrecision)]
        ]
    };
    
    var table5 = {
        type: "table",
        title: "⏱️ 运行统计",
        cols: ["项目", "数值"],
        rows: [
            ["运行时间", hours + "时" + mins + "分"],
            ["循环次数", stats.cycleCount],
            ["下单次数", stats.orderCount],
            ["撤单次数", stats.cancelCount],
            ["休眠时间", sleeptime + " ms"]
        ]
    };
    
    var table6 = {
        type: "table",
        title: "⚙️ 精度与参数",
        cols: ["参数", "值"],
        rows: [
            ["交易符号", symbol],
            ["价格精度", pricePrecision],
            ["数量精度", amountPrecision],
            ["最小下单量", minQty],
            ["价格步长", tickSize],
            ["基础下单量", baseAmount],
            ["最大持仓量", maxPosition],
            ["退出时清仓", closeOnExit ? "✅ 是" : "❌ 否"]
        ]
    };
    
    var statusIcon = stats.isStopLoss ? "🛑 已止损" : (IsPositionOverload(pos) ? "⚠️ 仓位超标" : "🤖 运行中");
    var statusStr = statusIcon + " | " + _D() + " | 收益: " + _N(profit, 2) + " USDT (" + profitPercent + "%)\n";
    statusStr += "多仓: " + pos.long.amount + "/" + maxPosition + " (" + longRatio + "%) | ";
    statusStr += "空仓: " + pos.short.amount + "/" + maxPosition + " (" + shortRatio + "%) | 净: " + netPos + "\n";
    statusStr += "`" + JSON.stringify([table1, table2, table3, table4, table5, table6]) + "`";
    
    LogStatus(statusStr);
}

// 主交易逻辑
function onTick() {
    stats.cycleCount++;
    
    CleanLogs();
    
    var depth = _C(exchange.GetDepth);
    if (!depth || !depth.Bids || !depth.Asks || depth.Bids.length < 20 || depth.Asks.length < 20) {
        Log("深度数据不足,跳过本轮");
        Sleep(1000);
        return;
    }
    
    var account = _C(exchange.GetAccount);
    var pos = GetPosition();
    
    var equity = GetEquity(account, pos);
    stats.currentEquity = equity;
    
    if (stats.cycleCount % 10 === 0) {
        UpdateProfitChart(equity);
    }
    
    var buyPrice = GetPrice("Buy", depth);
    var sellPrice = GetPrice("Sell", depth);
    
    if ((sellPrice - buyPrice) <= diffprice) {
        // buyPrice = NormalizePrice(buyPrice - 10 * tickSize);
        // sellPrice = NormalizePrice(sellPrice + 10 * tickSize);

        buyPrice = NormalizePrice(buyPrice - diffprice/2);
        sellPrice = NormalizePrice(sellPrice + diffprice/2);
    }
    
    UpdateStatus(account, pos, depth, buyPrice, sellPrice, equity);
    
    if (CheckStopLoss(equity)) {
        if (pos.long.amount > 0 || pos.short.amount > 0) {
            CloseAllPositions("止损触发");
        } else {
            CancelPendingOrders();
        }
        Log("策略已止损,停止交易。如需继续,请手动重启策略。", "#FF0000");
        return;
    }
    
    CancelPendingOrders();
    
    EmergencyReduce(pos, depth);
    
    pos = GetPosition();
    
    var openLongAmount = CalcOpenAmount(pos, "long");
    var openShortAmount = CalcOpenAmount(pos, "short");
    var closeLongAmount = CalcCloseAmount(pos, "long");
    var closeShortAmount = CalcCloseAmount(pos, "short");
    
    var closeLongPrice = CalcClosePrice(pos, depth, "long");
    var closeShortPrice = CalcClosePrice(pos, depth, "short");
    
    if (openLongAmount > 0 && CheckFunds(account, buyPrice, openLongAmount)) {
        var orderId = exchange.CreateOrder(symbol, "buy", buyPrice, openLongAmount);
        if (orderId) stats.orderCount++;
    }
    
    if (pos.short.amount > 0 && closeShortAmount > 0) {
        var orderId = exchange.CreateOrder(symbol, "closesell", closeShortPrice, closeShortAmount);
        if (orderId) stats.orderCount++;
    }
    
    if (openShortAmount > 0 && CheckFunds(account, sellPrice, openShortAmount)) {
        var orderId = exchange.CreateOrder(symbol, "sell", sellPrice, openShortAmount);
        if (orderId) stats.orderCount++;
    }
    
    if (pos.long.amount > 0 && closeLongAmount > 0) {
        var orderId = exchange.CreateOrder(symbol, "closebuy", closeLongPrice, closeLongAmount);
        if (orderId) stats.orderCount++;
    }
}

// 初始化交易精度
function InitPrecision() {
    try {
        var markets = exchange.GetMarkets();
        if (markets && markets[symbol]) {
            var market = markets[symbol];
            
            // 获取基础精度信息
            pricePrecision = market.PricePrecision || 2;
            tickSize = market.TickSize || 0.01;
            minQty = market.MinQty || 0.001;
            
            // 从 MinQty 推断数量精度
            // 例如: MinQty=0.005 -> 精度3, MinQty=0.0001 -> 精度4
            var minQtyPrecision = GetPrecisionFromValue(minQty);
            
            // 从 TickSize 推断价格精度(作为备选验证)
            var tickSizePrecision = GetPrecisionFromValue(tickSize);
            
            // 数量精度取 AmountPrecision 和 MinQty推断精度 的较小值
            var declaredAmountPrecision = market.AmountPrecision || 8;
            amountPrecision = Math.min(declaredAmountPrecision, minQtyPrecision);
            
            // 价格精度取 PricePrecision 和 TickSize推断精度 的较小值
            pricePrecision = Math.min(pricePrecision, tickSizePrecision);
            
            Log("========== 精度信息 ==========");
            Log("市场返回 - PricePrecision:", market.PricePrecision, ", AmountPrecision:", market.AmountPrecision);
            Log("市场返回 - TickSize:", tickSize, ", MinQty:", minQty);
            Log("推断精度 - TickSize精度:", tickSizePrecision, ", MinQty精度:", minQtyPrecision);
            Log("最终使用 - 价格精度:", pricePrecision, ", 数量精度:", amountPrecision);
            Log("==============================");
            
            // 检查 baseAmount 是否满足最小下单量
            if (baseAmount < minQty) {
                Log("⚠️ 警告: baseAmount(" + baseAmount + ") 小于最小下单量(" + minQty + "),已自动调整", "#FF9900");
                baseAmount = minQty;
            }
            
            // 规范化 baseAmount
            baseAmount = NormalizeAmount(baseAmount);
            if (baseAmount === 0) {
                baseAmount = minQty;
            }
            Log("规范化后 baseAmount:", baseAmount);
        }
    } catch (e) {
        Log("获取精度失败,使用默认值: " + e.message, "#FF9900");
    }
}

// 初始化收益图表
function InitChart() {
    var chart = {
        __isStock: true,
        tooltip: { xDateFormat: '%Y-%m-%d %H:%M:%S, %A' },
        title: { text: '高频做市策略收益曲线' },
        xAxis: { type: 'datetime' },
        yAxis: {
            title: { text: '收益 (USDT)' },
            opposite: false
        },
        series: [{
            name: '收益',
            data: []
        }]
    };
    Chart(chart);
}

// 程序入口
function main() {
    LogReset(LOG_RESERVE_COUNT);
    LogProfitReset();
    
    InitChart();
    
    exchange.SetContractType("swap");
    
    symbol = exchange.GetCurrency() + ".swap";
    Log("交易符号:", symbol);
    
    // 测试是否支持Lighter
    if (!exchange.GetAccount()) {
        Log("账户初始化失败,请检查配置是否正确,托管者是否为最新版本!")
    }

    InitPrecision();
    
    stats.startTime = new Date().getTime();
    stats.lastLogCleanTime = stats.startTime;
    
    var initAccount = _C(exchange.GetAccount);
    var initPos = GetPosition();
    stats.initialEquity = GetEquity(initAccount, initPos);
    stats.maxEquity = stats.initialEquity;
    stats.currentEquity = stats.initialEquity;
    
    Log("========== 策略启动 ==========", "#00FF00");
    Log("初始权益:", _N(stats.initialEquity, 4), "USDT");
    Log("止损阈值:", _N(stats.initialEquity * stopLossRatio, 4), "USDT", "(" + (stopLossRatio * 100) + "%)");
    Log("最大持仓:", maxPosition);
    Log("退出时清仓:", closeOnExit ? "是" : "否");
    Log("初始账户:", initAccount);
    Log("初始持仓:", _C(exchange.GetPositions, symbol));
    
    while (true) {
        try {
            onTick();
        } catch (e) {
            Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message, "#FF0000");
        }
        Sleep(sleeptime);
    }
}

// 退出清理
function onexit() {
    Log("========== 策略停止 ==========", "#FF0000");
    
    if (closeOnExit) {
        Log("closeOnExit=true,执行退出清仓...", "#FF9900");
        CloseAllPositions("策略退出");
    } else {
        Log("closeOnExit=false,保留当前持仓和挂单", "#0000FF");
    }
    
    Log("----------------------------------------");
    Log("总循环: " + stats.cycleCount + ", 下单: " + stats.orderCount + ", 撤单: " + stats.cancelCount);
    Log("初始权益: " + _N(stats.initialEquity, 4) + " USDT");
    Log("最终权益: " + _N(stats.currentEquity, 4) + " USDT");
    Log("总收益: " + _N(stats.currentEquity - stats.initialEquity, 4) + " USDT");
    Log("收益率: " + _N((stats.currentEquity - stats.initialEquity) / stats.initialEquity * 100, 2) + " %");
    Log("最大回撤: " + _N(stats.maxDrawdown, 2) + " %");
    Log("----------------------------------------");
}

Reinício sem custos de estratégias antigas: FMZ + Lighter DEX + IA na prática

Você define as regras de edição dos parâmetros no FMZ para a IA, e ela pode até mesmo configurar todos os parâmetros da interface automaticamente. Para fins de explicação, configurei manualmente os parâmetros na interface de estratégia, conforme mostrado na imagem acima.

4. Negociação ao vivo

Reinício sem custos de estratégias antigas: FMZ + Lighter DEX + IA na prática

Reinício sem custos de estratégias antigas: FMZ + Lighter DEX + IA na prática

Reinício sem custos de estratégias antigas: FMZ + Lighter DEX + IA na prática

Sinceramente, o código escrito pela IA é muito melhor que o meu e raramente comete erros (desde que os requisitos estejam claramente descritos, preciso de apenas 3 a 4 iterações para que funcione de forma estável). Sinto que minha produtividade explodiu 💥 Embora pareça que a estratégia não esteja dando lucro agora 😂, o volume de negociações aumentou bastante.

Reinício sem custos de estratégias antigas: FMZ + Lighter DEX + IA na prática

Reinício sem custos de estratégias antigas: FMZ + Lighter DEX + IA na prática

5. Resumo

A reação química de FMZ + AI + Isqueiro

Ao refletir sobre essa experiência, tenho algumas considerações:

  • A isenção de taxas é realmente um divisor de águas. Muitas estratégias que eram teoricamente sólidas no passado foram derrotadas pelas taxas de transação, o “assassino invisível”. A política de taxa zero da Lighter deu a essas estratégias uma chance de ressurgir. Se você tiver estratégias semelhantes “adormecidas”, pode ser uma boa ideia desenterrá-las e experimentá-las.

  • A inteligência artificial reduziu significativamente as barreiras ao desenvolvimento de estratégias. Desta vez, quase não escrevi código manualmente; toda a reestruturação da estratégia foi feita usando IA. Isso era inimaginável antes. Para quem tem ideias de negociação, mas pouca experiência em programação, a combinação de IA e FMZ é, sem dúvida, uma grande vantagem.

  • A importância da rápida integração da FMZ com novas bolsas de valores. A FMZ pode se integrar rapidamente a exchanges emergentes como a Lighter, permitindo que os usuários aproveitem as oportunidades imediatamente. A API unificada também significa que suas estratégias podem ser facilmente migradas para novas plataformas.

Próximos passos

Em seguida, planejo:

  • Continue a otimizar os parâmetros desta estratégia.
  • Experimente mais tipos de estratégia que sejam adequados para um ambiente sem taxas.
  • Explore estratégias relevantes aplicáveis ​​ao Lighter.

Outras estratégias antigas incluem: Colheitadeira de Alho-poró OK, etc.

Obrigado pelo seu apoio.

Obrigado pela leitura. Sinta-se à vontade para enviar sugestões ou solicitações.

6. Isenção de responsabilidade

Este artigo tem fins meramente técnicos e de aprendizagem, não constituindo qualquer tipo de aconselhamento de investimento.

  • Riscos da estratégia: O código da estratégia apresentado neste artigo destina-se apenas a fins de demonstração técnica e não garante rentabilidade. A negociação quantitativa envolve riscos inerentes, e o desempenho em testes históricos ou em negociações reais de curto prazo não é indicativo de retornos futuros. Utilize a estratégia com cautela e somente após compreender completamente a sua lógica.
  • Riscos das DEXs: As exchanges descentralizadas (DEXs) envolvem riscos relacionados a contratos inteligentes, liquidez e congestionamento de rede. Como uma plataforma emergente, a estabilidade e a segurança a longo prazo da Lighter DEX ainda precisam ser verificadas pelo mercado.
  • Política de taxa de transação zero: As políticas de taxas de câmbio podem ser ajustadas a qualquer momento. Consulte os comunicados oficiais mais recentes da Lighter. Mesmo que as transações sejam gratuitas, taxas de gás on-chain ainda podem ser cobradas.
  • Código gerado por IA: O código de estratégia neste artigo foi gerado com o auxílio de IA. Embora tenha sido testado, podem existir erros ou falhas lógicas. Destina-se apenas a fins de aprendizagem e pesquisa.
  • Os usuários assumem todos os riscos: Os usuários são os únicos responsáveis ​​por quaisquer consequências decorrentes do uso de qualquer informação, código ou estratégia fornecida neste artigo. Os autores e a plataforma FMZ não se responsabilizam por quaisquer perdas diretas ou indiretas.

A negociação de criptomoedas envolve um alto grau de risco. Certifique-se de gerenciar seus riscos e negociar de forma racional.