avatar of 发明者量化-小小梦 发明者量化-小小梦
집중하다 사신
4
집중하다
1319
수행원

오래된 전략을 수수료 없이 재시작하기: FMZ + Lighter DEX + AI를 활용한 실전 적용

만든 날짜: 2026-01-22 09:30:47, 업데이트 날짜: 2026-01-22 18:12:51
comments   8
hits   582

[TOC]

오래된 전략을 수수료 없이 재시작하기: FMZ + Lighter DEX + AI를 활용한 실전 적용

머리말

최근 FMZ 양적 플랫폼이 공식적으로 통합되었습니다.Lighter DEX솔직히 처음 이 소식을 접했을 때는 별로 신경 쓰지 않았습니다. 시장에는 수많은 탈중앙화 거래소(DEX)가 있으니까요. 하지만 좀 더 자세히 알아보니 한 가지 특징이 눈에 띄었습니다. 바로 거래 수수료가 없다는 점입니다.

네, 맞습니다. Lighter DEX는 일반 거래자에게 수수료가 전혀 없습니다. 이 소식을 듣자마자 문득 예전에 수수료 때문에 접어두었던 전략들을 다시 활용해 볼 수 있지 않을까 하는 생각이 들었습니다. 그래서 FMZ를 개설했습니다…전략 스퀘어“고대”의 전략들을 찾아보며…

1. Lighter

이번에 새롭게 추가된 탈중앙화 거래소(DEX)에 대해서는 자세히 설명하지 않겠습니다. 관심 있는 분들은 관련 정보를 찾아보시기 바랍니다. 현재 사용자 경험은 상당히 좋습니다. Lighter는 탈중앙화 거래소의 투명성을 유지하면서도 중앙화 거래소와 유사한 성능을 제공하며, API 접근 빈도가 높음에도 비교적 안정적으로 작동합니다.

데이터 요약

다음은 몇 가지 정보를 정리한 것입니다.

구성

다음으로 FMZ 설정 방법에 대해 간략하게 소개하겠습니다.LighterFMZ 플랫폼의 거래 페이지에 Lighter API KEY 구성 정보를 추가하세요.

오래된 전략을 수수료 없이 재시작하기: FMZ + Lighter DEX + AI를 활용한 실전 적용

다음 세 가지 사항을 설정해야 합니다.

  • 서명 API 개인 키 이것은 지갑 개인 키가 아닙니다. 이 서명 개인 키는 주문 및 거래에 사용되는 개인 키이며, Lighter에 로그인하고 https://app.lighter.xyz에서 지갑을 연결한 후 생성됩니다.

오래된 전략을 수수료 없이 재시작하기: FMZ + Lighter DEX + AI를 활용한 실전 적용

  • Lighter 테스트 환경에 로그인하는 경우 생성되는 키는 테스트 환경 키이며, 여기서는 자세히 설명하지 않겠습니다.
  • 서명용 개인 키를 생성할 때는 인덱스를 지정해야 합니다. 0~2는 예약된 비트이며, 3부터는 인덱스를 지정할 수 있습니다.
  • 이러한 로그인 및 생성 단계에는 모두 지갑 서명이 필요하며, 저는 바이낸스 지갑을 사용했고 만족스러운 경험을 했습니다.

만들어진서명 개인 키해당 설정은 FMZ 교환 추가 페이지의 해당 제어 편집 상자에서 수행할 수 있습니다.

  • 중요 사항: 라이터 선물 계약 거래를 지원하려면 최신 버전의 수탁 관리 프로그램을 다운로드해야 합니다.

  • API 인덱스 서명용 개인 키에 해당하는 인덱스를 입력하십시오.

  • 계정 인덱스 Lighter의 API를 통해 계정 인덱스를 얻을 수 있습니다.

    • API 인터페이스:https://mainnet.zklighter.elliot.ai/api/v1/account?by=l1_address&value={钱包地址} 예를 들어, 브라우저에서 해당 주소에 직접 접속해 보세요.https://mainnet.zklighter.elliot.ai/api/v1/account?by=l1_address&value=0x123xxxx0x123xxxx이 주소는 예시일 뿐이며, 실제 사용 시에는 내용을 바꿔야 합니다. 반환된 데이터:
    {
      "code": 200,
      "total": 1,
      "accounts": [
        {
          "code": 0,
          "account_type": 0,
          "index": 1234567,
          "l1_address": "0x123xxxx",
    

    ~에"index": 1234567그것이 바로 귀하의 계정 인덱스입니다.

    • 초기 생성 과정은 USDC와 같은 자산이 이체될 때만 시작됩니다.Lighter계정

    • 메인넷 엔드포인트를 사용하여 얻은 인터페이스는 메인넷 계정 인덱스를 가져오고, 테스트넷 엔드포인트를 사용하여 얻은 인터페이스는 테스트넷 계정 인덱스를 가져온다는 점에 유의하십시오.

이 계정 색인을 작성해야 하는 이유는 무엇입니까?Lighter계정 인덱스를 기준으로 여러 계정을 구분하는 하위 계정 시스템이 있습니다. 하위 계정을 사용해야 하는 경우 여기에서 하위 계정의 계정 인덱스를 구성할 수 있습니다(하위 계정의 계정 인덱스는 위 링크를 통해 조회한 결과 반환되는 JSON 데이터에 표시됩니다).

2. FMZ에 대한 고대 전략

수수료 없음: 판도를 바꾸는 혁신

이 기능이 저를 가장 설레게 합니다. Lighter는 일반 거래자에게 수수료를 전혀 부과하지 않습니다.

  • 거래 수수료가 없다는 것은 무엇을 의미합니까?

고빈도 거래 전략은 더 이상 거래 수수료로 인해 수익이 “삭감”되지 않습니다. 메쉬 전략을 사용하면 더 조밀한 메쉬 간격을 설정할 수 있습니다. 차익거래 전략의 손익분기점이 상당히 낮아졌습니다. 이론적으로는 가능했지만 실제 거래 수수료 때문에 무산되었던 전략들이 마침내 활용될 자리를 찾았습니다.

고대 전략의 재조명: 거래 수수료 제로의 매력

전략 라이브러리 고고학

“수수료 없이 다시 활용할 수 있는 전략은 무엇일까?“라는 질문을 염두에 두고 FMZ 전략 라이브러리와 커뮤니티를 살펴보았습니다. 그러던 중 익숙한 전략 하나가 눈에 띄었습니다.

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

이 전략은 간단하고 직관적이지만, 거래 수수료가 있는 환경에서는 거의 항상 손실로 이어집니다. 하지만 Lighter처럼 거래 수수료가 없는 환경에서는 시도해 볼 만합니다.

자, 질문은 이렇습니다.

문제는 코드가 너무 오래되었다는 것입니다. 전략을 살펴보면 코드가 단순하고 무차별 대입 방식이며, UI 콘텐츠가 거의 없고 접근성 기능도 부족합니다. 누락된 기능의 몇 가지 예는 다음과 같습니다.

  • 일부 API 인터페이스가 더 이상 사용되지 않습니다.
  • 최신 위험 관리 모듈이 부족합니다.
  • 정보가 누락되었습니다.
  • 매출 통계 자료가 누락되었습니다.

이 코드를 수동으로 리팩토링한다고요? 솔직히 좀 부담스럽네요. 하지만 저는 “편리한” 해결책을 생각해냈습니다. 바로 AI에게 리팩토링을 맡기는 거죠.

3. 구조조정 전략

먼저, 안전장치를 마련해 두겠습니다. 이 글은 신흥 탈중앙화 거래소(DEX)에서 AI를 이용해 전략을 재구성하려는 탐색적 시도일 뿐이며, 재구성된 전략의 수익성을 보장하지는 않습니다. 자, 그럼 Claude를 사용하여 이 오래된 전략을 재구성해 보겠습니다. 코드를 처음부터 작성할 생각은 없으며, 제가 원하는 것은 다음과 같습니다.

  • 기존 전략의 핵심 논리를 유지하십시오.
  • FMZ의 최신 API 사양에 맞춰 조정되었습니다.
  • 필요한 위험 관리 및 로깅 모듈을 추가하세요.
  • 비교적 완전하고 명확한 정보가 표시됩니다.
  • 코드 로직을 적절하게 최적화하세요

원본 코드를 AI에게 제공하세요

원본 전략 코드를 복사하여 요구 사항과 함께 AI에 보냈습니다. 여러 차례의 대화와 조정 과정을 거쳐 AI는 재구성된 코드를 생성해 주었습니다.

bash: while :; do cat PROMPT.md | claude-code ; done
) (배울 점들)
/*
高频做市策略 - 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("----------------------------------------");
}

오래된 전략을 수수료 없이 재시작하기: FMZ + Lighter DEX + AI를 활용한 실전 적용

FMZ의 매개변수 편집 규칙을 AI에 알려주면 AI가 인터페이스의 모든 매개변수를 직접 설정해 줄 수도 있습니다. 설명을 위해 위 그림과 같이 전략 인터페이스의 매개변수를 수동으로 설정했습니다.

4. 실시간 거래

오래된 전략을 수수료 없이 재시작하기: FMZ + Lighter DEX + AI를 활용한 실전 적용

오래된 전략을 수수료 없이 재시작하기: FMZ + Lighter DEX + AI를 활용한 실전 적용

오래된 전략을 수수료 없이 재시작하기: FMZ + Lighter DEX + AI를 활용한 실전 적용

솔직히 말해서, AI가 작성한 코드가 제 것보다 훨씬 낫고, 오류도 거의 없어요 (요구사항만 명확하게 설명해주면 3~4번만 수정하면 안정적으로 작동하거든요). 생산성이 폭발적으로 증가한 것 같아요 💥 지금은 당장 수익이 나지는 않지만 😂, 거래량은 꽤 많이 늘었어요.

오래된 전략을 수수료 없이 재시작하기: FMZ + Lighter DEX + AI를 활용한 실전 적용

오래된 전략을 수수료 없이 재시작하기: FMZ + Lighter DEX + AI를 활용한 실전 적용

5. 요약

FMZ + AI + 라이터의 화학 반응

이 경험을 되돌아보니 몇 가지 생각이 듭니다.

  • 수수료가 없다는 것은 확실히 판도를 바꾸는 요소입니다. 과거에는 이론적으로 타당했던 많은 전략들이 거래 수수료라는 “보이지 않는 살인자” 때문에 무용지물이 되었습니다. 라이터의 수수료 무료 정책은 이러한 전략들이 다시 살아날 기회를 제공했습니다. 만약 여러분도 이와 유사한 “잠재적 전략”을 가지고 있다면, 다시 꺼내서 시도해 보는 것도 좋을 것입니다.

  • 인공지능은 전략 개발의 진입 장벽을 크게 낮췄습니다. 이번에는 직접 코드를 작성한 부분이 거의 없었고, 전략 재구축 작업 전체를 AI를 이용해 완료했습니다. 이전에는 상상도 할 수 없었던 일입니다. 트레이딩 아이디어는 있지만 프로그래밍 실력이 부족한 사람들에게 AI와 FMZ의 조합은 분명 큰 도움이 될 것입니다.

  • FMZ가 새로운 거래소와 신속하게 통합된 것의 가치 FMZ는 Lighter와 같은 신흥 거래소와 빠르게 통합되어 사용자가 기회를 즉시 포착할 수 있도록 지원합니다. 또한 통합 API를 통해 기존 전략을 새로운 플랫폼으로 손쉽게 이전할 수 있습니다.

다음 단계

다음으로, 저는 다음과 같은 계획을 가지고 있습니다.

  • 이 전략의 매개변수를 지속적으로 최적화하십시오.
  • 수수료가 없는 환경에 적합한 다른 전략 유형을 시도해 보세요.
  • Lighter에 적용 가능한 관련 전략을 살펴보세요.

다른 고대 전략으로는 OK 리크 하베스터 등이 있습니다.

응원해주셔서 감사합니다.

읽어주셔서 감사합니다. 의견이나 요청 사항이 있으시면 언제든지 말씀해 주세요.

6. 면책 조항

본 글은 기술적 정보 교환 및 학습 목적으로만 작성되었으며 투자 조언을 구성하지 않습니다.

  • 전략 위험: 본 문서에 제시된 전략 코드는 기술적 분석 목적으로만 제공되며 수익성을 보장하지 않습니다. 양적 거래는 본질적으로 위험을 수반하며, 과거 백테스팅 또는 단기 실거래 성과는 미래 수익을 보장하지 않습니다. 전략의 논리를 완전히 이해한 후에 신중하게 사용하십시오.
  • 탈중앙화 거래소(DEX)의 위험성: 탈중앙화 거래소(DEX)는 스마트 계약 위험, 유동성 위험, 네트워크 혼잡 위험을 수반합니다. 신흥 플랫폼인 Lighter DEX의 장기적인 안정성과 보안은 시장에서 검증되어야 합니다.
  • 거래 수수료 무료 정책: 거래 수수료 정책은 언제든지 조정될 수 있습니다. Lighter의 최신 공식 공지사항을 참조하십시오. 거래 수수료가 무료인 경우에도 온체인 가스 수수료가 발생할 수 있습니다.
  • AI 생성 코드: 이 글에 제시된 전략 코드는 AI의 도움을 받아 생성되었습니다. 테스트를 거쳤지만, 잠재적인 버그나 논리적 오류가 존재할 수 있습니다. 학습 및 연구 목적으로만 사용하십시오.
  • 사용자는 모든 위험을 감수해야 합니다. 본 문서에 제공된 정보, 코드 또는 전략의 사용으로 인해 발생하는 모든 결과에 대한 책임은 전적으로 사용자에게 있습니다. 저자 및 FMZ 플랫폼은 직간접적인 손실에 대해 어떠한 책임도 지지 않습니다.

암호화폐 거래는 높은 위험을 수반합니다. 위험 관리에 유의하시고 합리적인 거래를 하시기 바랍니다.