[TOC]

Недавно была официально интегрирована количественная платформа FMZ.Lighter DEXЧестно говоря, я не обратил особого внимания на эту новость, когда впервые её увидел — в конце концов, на рынке бесчисленное множество децентрализованных бирж (DEX). Но, узнав о ней больше, я обратил внимание на одну особенность: нулевая комиссия за транзакции.
Да, вы всё правильно прочитали. Lighter DEX предлагает нулевую комиссию для обычных трейдеров. Это сразу же напомнило мне кое-что: смогу ли я наконец-то вернуть те стратегии, которые я «отложил» много лет назад из-за комиссионных сборов? Поэтому я открыл FMZ…Стратегический квадратВ поисках стратегий тех «древних времен»…
Я не буду вдаваться в подробности об этой недавно добавленной децентрализованной бирже (DEX); заинтересованные лица могут найти дополнительную информацию в интернете. В настоящее время пользовательский опыт довольно хорош. С точки зрения пользовательского опыта, Lighter предлагает производительность, сравнимую с централизованными биржами, сохраняя при этом децентрализованную прозрачность, и остается относительно стабильным даже при частом доступе к API.
Вот некоторая собранная информация:
Далее я кратко расскажу, как настроить FMZ.LighterДобавьте информацию о конфигурации ключа API Lighter на страницу обмена данными платформы FMZ.

Необходимо настроить три параметра:

созданныйПодпись закрытого ключаНастройки можно выполнить в соответствующем поле редактирования элемента управления на странице добавления биржи FMZ.
Важное примечание: Для поддержки биржи фьючерсных контрактов Lighter необходимо загрузить последнюю версию программы для хранения ценных бумаг.
Индекс API Введите индекс, соответствующий закрытому ключу подписи.
Указатель счетов Индексы учетных записей можно получить через API Lighter:
https://mainnet.zklighter.elliot.ai/api/v1/account?by=l1_address&value={钱包地址}
Например, перейдите по адресу непосредственно в браузере:https://mainnet.zklighter.elliot.ai/api/v1/account?by=l1_address&value=0x123xxxx,0x123xxxxЭто всего лишь пример адреса; замените это содержимое при использовании на практике.
Возвращенные данные:{
"code": 200,
"total": 1,
"accounts": [
{
"code": 0,
"account_type": 0,
"index": 1234567,
"l1_address": "0x123xxxx",
в"index": 1234567Это ваш индекс учетной записи.
Процесс создания на начальном этапе начнётся только после перевода активов (таких как USDC).Lighterсчет
Обратите внимание, что интерфейс, полученный с использованием конечной точки основной сети, извлекает индекс учетных записей основной сети, тогда как интерфейс, полученный с использованием конечной точки тестовой сети, извлекает индекс учетных записей тестовой сети.
Зачем нам нужно заполнять этот указатель счетов? Потому чтоLighterСуществует система субсчетов, которая различает разные учетные записи на основе индекса учетной записи. Если вам необходимо использовать субсчет, вы можете настроить индекс учетной записи субсчета здесь (индекс учетной записи субсчета будет отображаться в данных JSON, возвращаемых ссылкой на запрос выше).
Больше всего меня радует именно эта функция. Lighter предлагает политику нулевой комиссии для обычных трейдеров.
В стратегиях высокочастотной торговли прибыль больше не “съедается” комиссионными сборами за транзакции. Стратегия построения сетки позволяет задать более плотное расположение элементов. Точка безубыточности для арбитражных стратегий значительно снизилась. Те стратегии, которые были «теоретически осуществимы, но на практике терпели неудачу из-за комиссионных сборов», наконец-то нашли свое применение.
Задавшись вопросом: «Какие стратегии можно возродить, не взимая комиссию за транзакции?», я начал изучать библиотеку стратегий FMZ и сообщество. Вскоре мое внимание привлекла знакомая стратегия:
Эта стратегия проста и понятна, но в условиях комиссий за транзакции она почти всегда приводит к убыткам. Однако в среде Lighter, где комиссия за транзакции отсутствует, её стоит попробовать.
Итак, вот в чем проблема: код слишком устарел. Если посмотреть на стратегию, код простой и построен методом грубой силы, практически без контента пользовательского интерфейса и без некоторых функций доступности. Вот несколько примеров того, чего не хватает:
Ручная рефакторизация этого кода? Честно говоря, это довольно сложно. Однако я придумал “ленивое” решение — пусть рефакторинг сделает за меня ИИ.
Для начала давайте оговоримся: эта статья — всего лишь попытка воссоздать стратегию с использованием ИИ на новой децентрализованной бирже, и мы не гарантируем прибыльность воссозданной стратегии. Итак, начнём воссоздавать эту старую стратегию с помощью Клода. Я не хочу писать код с нуля; мои требования таковы:
Я скопировал исходный код стратегии и отправил его вместе со своими требованиями ИИ. После нескольких раундов диалога и корректировок ИИ сгенерировал для меня переработанный код:
- 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, и ИИ может даже настроить все параметры интерфейса за вас напрямую. Для наглядности я вручную настроил параметры в интерфейсе стратегии, как показано на рисунке выше.



Честно говоря, код, написанный ИИ, намного лучше моего, и он редко ошибается (если требования четко описаны, мне нужно всего 3-4 итерации, чтобы он стабильно работал). Я чувствую, что моя производительность резко возросла 💥 Хотя, похоже, стратегия сейчас не приносит прибыли 😂, объем торгов значительно увеличился.


Оглядываясь назад на этот опыт, у меня есть несколько мыслей:
Отсутствие комиссий действительно меняет правила игры. Многие стратегии, которые в прошлом казались теоретически обоснованными, потерпели крах из-за комиссий за транзакции — «невидимого убийцы». Политика нулевых комиссий Lighter дала этим стратегиям шанс возродиться. Если у вас есть подобные «заброшенные стратегии», вы можете попробовать их использовать.
Искусственный интеллект значительно снизил барьер для разработки стратегий. На этот раз я практически не писал код вручную; вся реструктуризация стратегии была выполнена с помощью ИИ. Раньше это было немыслимо. Для тех, у кого есть торговые идеи, но ограниченные навыки программирования, сочетание ИИ и FMZ, несомненно, является большим преимуществом.
Ценность быстрой интеграции FMZ с новыми биржами FMZ может быстро интегрироваться с новыми биржами, такими как Lighter, позволяя пользователям немедленно использовать открывающиеся возможности. Единый API также означает, что ваши стратегии можно легко перенести на новые платформы.
Далее я планирую:
К другим древним стратегиям относятся: OK Leek Harvester и т.д.
Спасибо за прочтение. Пожалуйста, не стесняйтесь оставлять свои предложения или пожелания.
Данная статья предназначена исключительно для обмена техническим опытом и обучения и не является инвестиционной рекомендацией.
Торговля криптовалютами сопряжена с высокой степенью риска. Пожалуйста, обязательно управляйте своими рисками и торгуйте рационально.