avatar of 发明者量化-小小梦 发明者量化-小小梦
Suivre Messages privés
4
Suivre
1319
Abonnés

Redémarrage sans frais des stratégies anciennes : FMZ + Lighter DEX + IA en pratique

Créé le: 2026-01-22 09:30:47, Mis à jour le: 2026-01-22 18:12:51
comments   8
hits   582

[TOC]

Redémarrage sans frais des stratégies anciennes : FMZ + Lighter DEX + IA en pratique

Préface

La plateforme quantitative FMZ a été officiellement intégrée récemment.Lighter DEXHonnêtement, je n’y ai pas prêté beaucoup d’attention au départ ; après tout, il existe d’innombrables plateformes d’échange décentralisées (DEX) sur le marché. Mais après m’être renseigné, une caractéristique a particulièrement retenu mon attention : l’absence de frais de transaction.

Oui, vous avez bien lu. Lighter DEX propose des frais de commission nuls pour les traders réguliers. Cela m’a immédiatement rappelé quelque chose : pourrais-je enfin ressortir ces stratégies que j’avais mises de côté il y a des années à cause des frais de commission ? Alors, j’ai ouvert FMZ…Place de la stratégieÀ la recherche de stratégies issues de ces « temps anciens »…

1. Lighter

Je ne m’étendrai pas trop sur ce nouveau DEX ; les personnes intéressées peuvent se renseigner davantage. Actuellement, l’expérience utilisateur est très satisfaisante. Lighter offre des performances comparables aux plateformes d’échange centralisées tout en préservant la transparence décentralisée, et reste relativement stable même avec un accès API fréquent.

Résumé des données

Voici quelques informations compilées :

Configuration

Ensuite, je présenterai brièvement comment configurer FMZ.LighterAjoutez les informations de configuration de la clé API Lighter sur la page d’échange de la plateforme FMZ.

Redémarrage sans frais des stratégies anciennes : FMZ + Lighter DEX + IA en pratique

Trois éléments doivent être configurés :

  • Clé privée de l’API de signature Il ne s’agit pas de la clé privée de votre portefeuille. Cette clé privée de signature est utilisée pour passer des ordres et effectuer des transactions ; elle est créée après vous être connecté à Lighter et avoir associé votre portefeuille à l’adresse https://app.lighter.xyz.

Redémarrage sans frais des stratégies anciennes : FMZ + Lighter DEX + IA en pratique

  • Si vous vous connectez à l’environnement de test Lighter, la clé créée sera la clé de l’environnement de test, qui ne sera pas détaillée ici.
  • Lors de la création d’une clé privée de signature, vous devez spécifier un index. Les bits 0 à 2 sont réservés ; vous pouvez spécifier un index à partir de 3.
  • Ces étapes de connexion et de création nécessitent toutes une signature de portefeuille ; j’ai utilisé Binance Wallet et j’ai eu une bonne expérience.

CrééClé privée de signatureLa configuration peut être effectuée dans la zone de texte de contrôle correspondante sur la page FMZ Ajouter un échange.

  • Remarque importante : Vous devez télécharger la dernière version du logiciel de conservation pour prendre en charge la bourse de contrats à terme Lighter.

  • Index des API Saisissez l’index correspondant à la clé privée de signature.

  • Index des comptes Les index des comptes peuvent être obtenus via l’API de Lighter :

    • Interface API :https://mainnet.zklighter.elliot.ai/api/v1/account?by=l1_address&value={钱包地址} Par exemple, accédez directement à l’adresse dans votre navigateur :https://mainnet.zklighter.elliot.ai/api/v1/account?by=l1_address&value=0x123xxxx0x123xxxxCeci n’est qu’une adresse d’exemple ; remplacez ce contenu lorsque vous l’utiliserez en pratique. Données renvoyées :
    {
      "code": 200,
      "total": 1,
      "accounts": [
        {
          "code": 0,
          "account_type": 0,
          "index": 1234567,
          "l1_address": "0x123xxxx",
    

    dans"index": 1234567Voici l’index de votre compte.

    • Le processus de création initial ne commencera que lorsque les actifs (tels que les USDC) seront transférés.Lightercompte

    • Notez que l’interface obtenue via le point de terminaison du réseau principal récupère l’index du compte du réseau principal, tandis que l’interface obtenue via le point de terminaison du réseau de test récupère l’index du compte du réseau de test.

Pourquoi devons-nous remplir cet index des comptes ? Parce queLighterUn système de sous-comptes permet de distinguer les différents comptes grâce à leur index. Si vous souhaitez utiliser un sous-compte, vous pouvez configurer son index ici (cet index apparaîtra dans les données JSON renvoyées par le lien de requête ci-dessus).

2. Stratégies anciennes sur FMZ

Zéro frais : une révolution

C’est cette fonctionnalité qui me séduit le plus. Lighter propose une politique de zéro frais pour les traders réguliers.

  • Que signifie « zéro frais de transaction » ?

Les stratégies de trading haute fréquence ne voient plus leurs profits « grignotés » par les frais de transaction. La stratégie de maillage permet de définir un espacement de maillage plus dense. Le seuil de rentabilité des stratégies d’arbitrage a été considérablement réduit. Ces stratégies qui étaient « théoriquement réalisables mais, en pratique, contrecarrées par les frais de transaction » ont finalement trouvé une application.

Une stratégie ancestrale mise au jour : l’attrait des frais de transaction nuls

Archéologie de la bibliothèque stratégique

Avec en tête la question « Quelles stratégies peuvent être relancées sans frais de transaction ? », j’ai commencé à explorer la bibliothèque de stratégies et la communauté FMZ. Rapidement, une stratégie familière a attiré mon attention :

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

Cette stratégie est simple et directe, mais dans un environnement où des frais de transaction s’appliquent, elle se solde presque toujours par une perte. Cependant, dans l’environnement sans frais de transaction de Lighter, elle mérite d’être tentée.

Voici donc la question :

Voici le problème : le code est trop ancien. L’analyse de la stratégie révèle un code simple et rudimentaire, quasiment dépourvu d’interface utilisateur et présentant des lacunes en matière d’accessibilité. Voici quelques exemples de ce qui manque :

  • Certaines interfaces API sont obsolètes.
  • Il est dépourvu de modules modernes de contrôle des risques.
  • Des informations sont manquantes.
  • Les statistiques sur les revenus sont manquantes.

Refactoriser ce code manuellement ? Franchement, c’est un peu intimidant. Mais j’ai trouvé une solution de facilité : laisser l’IA s’en charger.

3. Stratégie de restructuration

Avant toute chose, précisons que cet article n’est qu’une tentative exploratoire de reconstruction d’une stratégie à l’aide de l’IA sur une plateforme d’échange décentralisée émergente, et nous ne garantissons pas la rentabilité de la stratégie reconstruite. Commençons donc à reconstruire cette stratégie ancestrale avec Claude. Je ne souhaite pas coder à partir de zéro ; voici mes exigences :

  • Conserver la logique fondamentale de la stratégie originale
  • Adapté aux dernières spécifications API de FMZ
  • Ajouter les modules de contrôle des risques et de journalisation nécessaires
  • Les informations affichées sont relativement complètes et claires.
  • Optimiser la logique du code de manière appropriée

Fournir le code original à l’IA

J’ai copié le code stratégique original et l’ai envoyé à l’IA avec mes exigences. Après plusieurs échanges et ajustements, l’IA a généré le code remanié.

bash: while :; do cat PROMPT.md | claude-code ; done
) (Pensées à retenir)
/*
高频做市策略 - 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("----------------------------------------");
}

Redémarrage sans frais des stratégies anciennes : FMZ + Lighter DEX + IA en pratique

Vous indiquez à l’IA les règles de modification des paramètres sur FMZ, et elle peut même configurer directement les paramètres d’interface. À titre d’exemple, j’ai configuré manuellement les paramètres de l’interface de stratégie, comme illustré ci-dessus.

4. Trading en direct

Redémarrage sans frais des stratégies anciennes : FMZ + Lighter DEX + IA en pratique

Redémarrage sans frais des stratégies anciennes : FMZ + Lighter DEX + IA en pratique

Redémarrage sans frais des stratégies anciennes : FMZ + Lighter DEX + IA en pratique

Honnêtement, le code généré par l’IA est bien meilleur que le mien et il fait rarement des erreurs (tant que les exigences sont clairement définies, 3 ou 4 itérations suffisent pour obtenir un fonctionnement stable). Ma productivité a explosé ! 💥 Même si la stratégie ne semble pas encore rentable 😂, le volume de transactions a considérablement augmenté.

Redémarrage sans frais des stratégies anciennes : FMZ + Lighter DEX + IA en pratique

Redémarrage sans frais des stratégies anciennes : FMZ + Lighter DEX + IA en pratique

5. Résumé

Réaction chimique de FMZ + AI + briquet

En repensant à cette expérience, voici quelques réflexions :

  • L’absence de frais change véritablement la donne. De nombreuses stratégies, théoriquement solides par le passé, ont été compromises par les frais de transaction, ce « tueur invisible ». La politique de zéro frais de Lighter leur offre une nouvelle chance. Si vous avez des stratégies similaires « dormantes », pourquoi ne pas les ressortir et les tester ?

  • L’IA a considérablement abaissé les barrières au développement stratégique. Cette fois-ci, j’ai à peine écrit une ligne de code ; la restructuration complète de la stratégie a été réalisée grâce à l’IA. C’était impensable auparavant. Pour ceux qui ont des idées de trading mais des compétences limitées en programmation, l’association de l’IA et de FMZ est sans aucun doute un atout précieux.

  • L’intérêt d’une intégration rapide de FMZ avec les nouvelles bourses FMZ s’intègre rapidement aux plateformes d’échange émergentes comme Lighter, permettant ainsi aux utilisateurs de saisir immédiatement les opportunités. Son API unifiée facilite également la migration de vos stratégies vers ces nouvelles plateformes.

Prochaines étapes

Ensuite, je prévois de :

  • Continuez d’optimiser les paramètres de cette stratégie.
  • Essayez d’autres types de stratégies adaptés à un environnement sans frais.
  • Explorez les stratégies pertinentes applicables à Lighter.

Parmi les autres stratégies anciennes, on peut citer : OK Leek Harvester, etc.

Merci pour votre soutien.

Merci de votre lecture. N’hésitez pas à nous faire part de vos suggestions ou demandes.

6. Clause de non-responsabilité

Cet article est uniquement destiné à des fins d’échange technique et d’apprentissage et ne constitue en aucun cas un conseil en investissement.

  • Risques liés à la stratégie : Le code de stratégie présenté dans cet article est fourni à titre de démonstration technique uniquement et ne garantit aucune rentabilité. Le trading quantitatif comporte intrinsèquement des risques, et les performances passées, qu’il s’agisse de tests rétrospectifs ou de transactions réelles à court terme, ne préjugent en rien des performances futures. Veuillez utiliser cette stratégie avec prudence et uniquement après en avoir parfaitement compris le fonctionnement.
  • Risques liés aux DEX : Les plateformes d’échange décentralisées (DEX) comportent des risques liés aux contrats intelligents, à la liquidité et à la congestion du réseau. En tant que plateforme émergente, la stabilité et la sécurité à long terme de Lighter DEX restent à confirmer par le marché.
  • Politique de frais de transaction nuls : Les politiques relatives aux frais d’échange peuvent être modifiées à tout moment. Veuillez consulter les dernières annonces officielles de Lighter. Même si les transactions sont gratuites, des frais de gaz peuvent être appliqués sur la blockchain.
  • Code généré par IA : Le code stratégique présenté dans cet article a été généré à l’aide d’une IA. Bien qu’il ait été testé, des bogues ou des erreurs logiques peuvent subsister. Il est destiné uniquement à des fins d’apprentissage et de recherche.
  • L’utilisateur assume l’entière responsabilité des conséquences découlant de l’utilisation des informations, codes ou stratégies présentés dans cet article. Les auteurs et la plateforme FMZ déclinent toute responsabilité en cas de pertes directes ou indirectes.

Le trading de cryptomonnaies comporte un risque élevé. Veuillez gérer vos risques et trader de manière rationnelle.