[TOC]

Благодаря быстрому развитию технологий искусственного интеллекта (ИИ) они продемонстрировали чрезвычайно высокую эффективность и креативность во многих областях. Количественная торговля, как высокотехничная область, естественно, также активно изучает возможности применения искусственного интеллекта. Однако на практике мы обнаружим, что при использовании исключительно ИИ для непосредственной генерации полных, стабильных и устойчиво прибыльных торговых стратегий по-прежнему возникают серьезные проблемы.
Особенно новым пользователям платформы из-за их слабых навыков программирования сложно реализовать свои торговые идеи в кодах стратегий. Хотя в настоящее время мы можем сообщать ИИ наши идеи и позволять ему выдавать стратегии. Однако эффект от внедрения не совсем оправдал ожидания. Я часто сталкиваюсь с пользователями, которые задают вопросы с помощью кодов, сгенерированных ИИ, и иногда я могу сразу увидеть стратегии, сгенерированные ИИ. Поскольку на данном этапе все еще существует много проблем с кодами стратегий, генерируемыми ИИ, такое использование ИИ не только не решает никаких проблем, но и вносит еще больше путаницы и проблем для новичков. Чем больше я узнавал, тем больше запутывался, и в конце концов «бросил попытки начать».
Лично я считаю, что существуют две основные причины текущих проблем со стратегиями прямого вывода ИИ:
Итак, существуют ли другие, более эффективные методы применения? В этой статье мы хотим поделиться новым образом мышления: пусть ИИ поможет нам изучить существующие стратегии, понять их структуру, извлечь ключевые детали и методы, а также провести дальнейший анализ их эффективности и возможностей для улучшения. Этот метод может не только помочь нам быстрее понять суть разработки стратегии, но и систематически повышать наш уровень количественной торговли.
Используя преимущества ИИ, ИИ может относительно точно понимать анализ конкретного кода, поскольку для ИИ данные кода представляют собой «1 есть 1, 2 есть 2», и не будет никакой логической путаницы, двусмысленности или других проблем, вызванных требованиями описания естественного языка. Так почему бы не использовать преимущества ИИ, чтобы сократить объем ручной работы и в полной мере раскрыть преимущества ручного труда?
Его можно разделить на следующие этапы:
Выберите существующую стратегию Это может быть самостоятельно написанная программа с открытым исходным кодом или отличный пример стратегии на количественной платформе изобретателя.
Пусть ИИ поможет нам объяснить стратегию
Понять общую идею
Разберите функциональные модули каждой части.
Уточните используемые индикаторы, параметры и торговую логику.
В каких рыночных условиях стратегия работает лучше?
Каковы возможные точки риска?
Какие области можно оптимизировать и улучшить?
Тестирование на исторических данных по разным продуктам и периодам
Добавьте дополнительные фильтры или меры контроля рисков
Наблюдайте за изменениями в производительности и формируйте собственные идеи
Давайте позволим ИИ изучить стратегию и объяснить ее нам, чтобы увидеть, соответствует ли она нашим ожиданиям. Это может помочь нам научиться количественной оценке.
Разработка и реализация пошаговой торговой стратегии увеличения позиции на основе фильтрации тренда EMA Адрес стратегии: https://www.fmz.com/strategy/492116
/*backtest
start: 2024-10-01 00:00:00
end: 2025-04-23 00:00:00
period: 1h
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDT"}]
args: [["targetProfit",20],["amount",20],["amountPrecision",3],["isAmountForUSDT",true]]
*/
function getTotalEquity_OKEX_V5() {
var totalEquity = null
var ret = exchange.IO("api", "GET", "/api/v5/account/balance", "ccy=USDT")
if (ret) {
try {
totalEquity = parseFloat(ret.data[0].details[0].eq)
} catch(e) {
Log("获取账户总权益失败!")
return null
}
}
return totalEquity
}
function getTotalEquity_Binance() {
var totalEquity = null
var ret = exchange.GetAccount()
if (ret) {
try {
totalEquity = parseFloat(ret.Info.totalWalletBalance)
} catch(e) {
Log("获取账户总权益失败!")
return null
}
}
return totalEquity
}
function getTotalEquity() {
var exName = exchange.GetName()
if (exName == "Futures_OKCoin") {
return getTotalEquity_OKEX_V5()
} else if (exName == "Futures_Binance") {
return getTotalEquity_Binance()
} else {
throw "不支持该交易所"
}
}
function ceilToDecimals(value, decimals) {
const factor = Math.pow(10, decimals);
return Math.ceil(value * factor) / factor;
}
function cancelAll() {
while (1) {
var orders = _C(exchange.GetOrders)
if (orders.length == 0) {
break
}
for (var i = 0 ; i < orders.length ; i++) {
exchange.CancelOrder(orders[i].Id, orders[i])
Sleep(interval)
}
Sleep(interval)
}
}
function trade(distance, price, amount) {
var tradeFunc = null
if (distance == "buy") {
tradeFunc = exchange.Buy
} else if (distance == "sell") {
tradeFunc = exchange.Sell
} else if (distance == "closebuy") {
tradeFunc = exchange.Sell
} else {
tradeFunc = exchange.Buy
}
exchange.SetDirection(distance)
return tradeFunc(price, amount)
}
function openLong(price, amount) {
return trade("buy", price, amount)
}
function openShort(price, amount) {
return trade("sell", price, amount)
}
function coverLong(price, amount) {
return trade("closebuy", price, amount)
}
function coverShort(price, amount) {
return trade("closesell", price, amount)
}
function plotRecords(c, buyOrder, sellOrder, pos) {
var bars = _C(exchange.GetRecords)
if (bars.length == 0) {
return
}
bars.forEach(function(bar, index) {
c.begin(bar)
if (index == bars.length - 1) {
if (buyOrder) {
c.hline(buyOrder.Price, "buy", "rgba(255, 0, 0, 0.2)", "dotted")
}
if (sellOrder) {
c.hline(sellOrder.Price, "sell", "rgba(0, 255, 0, 0.2)", "dotted")
}
if (pos && pos.length == 1) {
c.hline(pos[0].Price, "pos", "rgba(0, 0, 255, 0.2)", "dashed")
}
}
c.close()
})
}
var buyOrderId = null
var sellOrderId = null
var logStatusMsgBuff = ""
function main() {
var exName = exchange.GetName()
if (isSimulate && exName == "Futures_OKCoin") {
exchange.IO("simulate", true)
}
if (isReset) {
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("重置所有数据", "#FF0000")
}
exchange.SetContractType(contractType)
exchange.SetPrecision(pricePrecision, amountPrecision)
Log("设置精度", pricePrecision, amountPrecision)
exchange.SetMarginLevel(marginLevel)
if (totalEq == -1 && !IsVirtual()) {
var recoverTotalEq = _G("totalEq")
if (!recoverTotalEq) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
totalEq = currTotalEq
_G("totalEq", currTotalEq)
} else {
throw "获取初始权益失败"
}
} else {
totalEq = recoverTotalEq
}
}
var addCounter = _G("addCounter")
if (!addCounter) {
addCounter = 1
if (setAddCounter != -1) {
addCounter = setAddCounter
}
_G("addCounter", addCounter)
} else {
addCounter -= 1
}
let c = KLineChart({
overlay: true
})
var isLock = false
while (true) {
var ticker = _C(exchange.GetTicker)
var pos = _C(exchange.GetPosition)
if (pos.length > 1) {
Log(pos)
throw "同时有多空持仓"
}
var r = _C(exchange.GetRecords, 60 * 60)
var ema = TA.EMA(r, 60)
if (Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2] > 0.03) {
cancelAll()
isLock = true
}
if (Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2] < 0.02) {
isLock = false
}
if (isLock) {
LogStatus(_D(), "暂停, 检测阈值:", _N(Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2], 3), logStatusMsgBuff)
plotRecords(c, null, null, pos)
Sleep(interval)
continue
}
var currentAcc = _C(exchange.GetAccount)
if (currentAcc.Balance < totalEq * reserve) {
throw "no money, stop"
}
if (addCounter > maxAddCounter) {
LogStatus(_D(), "加仓已达到上限", logStatusMsgBuff)
if (isMaxAddCounterClear && pos.length >= 1) {
Log("加仓已达到上限,撤单,清仓")
cancelAll()
if (pos[0].Type == PD_LONG) {
var coverId = coverLong(-1, pos[0].Amount)
} else if (pos[0].Type == PD_SHORT) {
var coverId = coverShort(-1, pos[0].Amount)
}
addCounter = 1
}
continue
}
if (pos.length == 0) {
if (!IsVirtual()) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
LogProfit(currTotalEq - totalEq, "当前总权益:", currTotalEq)
}
}
var tradeAmountLong = amount
var tradeAmountShort = amount
if (isAmountForUSDT) {
tradeAmountLong = ceilToDecimals(tradeAmountLong * 1.01 / (ticker.Last - targetProfit / 5) / oneCtValue, amountPrecision)
tradeAmountShort = ceilToDecimals(tradeAmountShort * 1.01 / (ticker.Last + targetProfit / 5) / oneCtValue, amountPrecision)
}
buyOrderId = openLong(ticker.Last - targetProfit / 5, tradeAmountLong)
sellOrderId = openShort(ticker.Last + targetProfit / 5, tradeAmountShort)
addCounter = 1
_G("addCounter", addCounter)
} else if (pos[0].Type == PD_LONG) {
var n = ratio
var price = ticker.Last
var addAmount = isDoubling ? pos[0].Amount : (isAmountForUSDT ? (ceilToDecimals(amount * 1.01 / (price - targetProfit * n) / oneCtValue, amountPrecision)) : amount)
buyOrderId = openLong(price - targetProfit * n, addAmount)
sellOrderId = coverLong(pos[0].Price + targetProfit, pos[0].Amount)
addCounter++
_G("addCounter", addCounter)
} else if (pos[0].Type == PD_SHORT) {
var n = ratio
var price = ticker.Last
var addAmount = isDoubling ? pos[0].Amount : (isAmountForUSDT ? (ceilToDecimals(amount * 1.01 / (price + targetProfit * n) / oneCtValue, amountPrecision)) : amount)
buyOrderId = coverShort(pos[0].Price - targetProfit, pos[0].Amount)
sellOrderId = openShort(price + targetProfit * n, addAmount)
addCounter++
_G("addCounter", addCounter)
}
if (!sellOrderId || !buyOrderId) {
cancelAll()
buyOrderId = null
sellOrderId = null
continue
}
while (1) {
var isFindBuyId = false
var isFindSellId = false
var orders = _C(exchange.GetOrders)
var buyOrder = null
var sellOrder = null
for (var i = 0 ; i < orders.length ; i++) {
if (buyOrderId == orders[i].Id) {
isFindBuyId = true
buyOrder = orders[i]
}
if (sellOrderId == orders[i].Id) {
isFindSellId = true
sellOrder = orders[i]
}
}
if (!isFindSellId && !isFindBuyId) {
cancelAll()
break
} else if (!isFindBuyId) {
Log("买单成交")
cancelAll()
break
} else if (!isFindSellId) {
Log("卖单成交")
cancelAll()
break
}
var acc = _C(exchange.GetAccount)
var tbl = {"type": "table", "title": "data", "cols": ["data", "symbol", "type", "price", "amount"], "rows": []}
if (buyOrder) {
tbl.rows.push(["订单", buyOrder.Symbol, buyOrder.Type == ORDER_TYPE_BUY ? "买入" : "卖出", buyOrder.Price, buyOrder.Amount])
}
if (sellOrder) {
tbl.rows.push(["订单", sellOrder.Symbol, sellOrder.Type == ORDER_TYPE_BUY ? "买入" : "卖出", sellOrder.Price, sellOrder.Amount])
}
if (pos && pos.length == 1) {
tbl.rows.push(["持仓", pos[0].Symbol, pos[0].Type == PD_LONG ? "多" : "空", pos[0].Price, pos[0].Amount])
}
logStatusMsgBuff = "当前权益:" + acc.Equity + ", 初始权益:" + totalEq + (!IsVirtual() ? ", 浮动盈亏:" + (acc.Equity - totalEq) : "") + ", 加仓次数:" + addCounter + "\n`" + JSON.stringify(tbl) + "`"
LogStatus(_D(), "当前权益:", acc.Equity, ", 初始权益:", totalEq, !IsVirtual() ? ", 浮动盈亏:" + (acc.Equity - totalEq) : "", ", 加仓次数:" + addCounter, "\n`" + JSON.stringify(tbl) + "`")
plotRecords(c, buyOrder, sellOrder, pos)
Sleep(interval)
}
Sleep(interval)
}
}
function onexit() {
Log("扫尾,撤销所有挂单")
cancelAll()
}
Для новых пользователей платформы FMZ вид такой кучи кодов может вызвать чувство растерянности. Вместо того чтобы изучать код строка за строкой, мы могли бы (проявить ленивость) и передать его ИИ, позволить ИИ объяснить нам и повысить эффективность обучения.
Здесь я использую GPT, и следующий контент объясняется с помощью искусственного интеллекта:
Обзор В этой статье будет представлена пошаговая торговая стратегия увеличения позиции, основанная на фильтрации тренда EMA (экспоненциальной скользящей средней). Эта стратегия в основном используется на Binance Futures (Futures_Binance), поддерживает 1-часовое бэктестирование и основана на 1-минутной агрегации данных K-line. Отслеживая в режиме реального времени отклонение между ценой и EMA, стратегия динамически переключает режимы торговли (обычная торговля/приостановленная торговля), постепенно увеличивает позиции на стабильном рынке и автоматически приостанавливает позиции при аномальных колебаниях, чтобы избежать рисков.
flowchart TD
开始 --> 初始化参数
初始化参数 --> 账户余额检查
账户余额检查 --> 计算EMA
计算EMA --> 判断是否锁仓
判断是否锁仓 -->|是| 暂停交易
判断是否锁仓 -->|否| 正常交易
正常交易 --> 是否有持仓
是否有持仓 -->|无| 首次挂单
是否有持仓 -->|有| 按持仓方向加仓与止盈挂单
首次挂单 --> 等待成交
按持仓方向加仓与止盈挂单 --> 等待成交
等待成交 --> 挂单成交检测
挂单成交检测 --> 成交后调整
成交后调整 --> 更新加仓次数
更新加仓次数 --> 是否超出最大加仓次数
是否超出最大加仓次数 -->|是| 平仓
是否超出最大加仓次数 -->|否| 继续交易
Пятое: резюме Эта пошаговая стратегия увеличения позиции на основе фильтрации EMA учитывает как доходность, так и контроль рисков и подходит для работы на волатильном и слабоволатильном рынке. Благодаря гибким методам добавления позиций и механизмам приостановки тренда можно эффективно снизить вероятность ликвидации и повысить эффективность использования капитала. Он поддерживает как бэктестинг, так и реальную торговлю, а его модульная конструкция позволяет легко расширять его. Например, он может дополнительно ввести динамическую корректировку targetProfit и суммы или добавить другие технические индикаторы для усиления эффекта фильтрации.
Относительно вопросов GPT:

Следующий контент поясняется ИИ:
В этой стратегии фильтрация тенденций достигается за счет:
var ema = TA.EMA(r, 60)
if (Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2] > 0.03) {
cancelAll()
isLock = true
}
if (Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2] < 0.02) {
isLock = false
}
if (isLock) {
LogStatus(_D(), "暂停, 检测阈值:", _N(Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2], 3), logStatusMsgBuff)
plotRecords(c, null, null, pos)
Sleep(interval)
continue
}
Блокировка и снятие тренда: Сравнивая разницу между текущей ценой (ticker.Last) и значением EMA предыдущего часа, вычисляется процент отклонения цены от EMA. Math.abs(ticker.Last - ema[ema.length - 2]) / ema[ema.length - 2] вычисляет процентное отклонение текущей цены от EMA предыдущего часа. Если отклонение превышает 3% (> 0,03), то считается, что рыночная тенденция существенно изменилась, и вызывается функция cancelAll() для отмены всех отложенных ордеров, а isLock устанавливается в значение true, т. е. позиция блокируется, предотвращая дальнейшую торговлю. Если цена отклоняется от EMA менее чем на 2% (< 0,02), состояние блокировки снимается и isLock устанавливается в значение false.
Приостановка торговли: Если isLock имеет значение true (что указывает на то, что позиция в данный момент заблокирована), никакие дальнейшие торговые операции выполняться не будут. Программа выведет записи журнала и вызовет plotRecords() для построения диаграммы, показывающей текущую тенденцию и статус положения. Используйте Sleep(interval), чтобы сделать паузу на определенный период времени, а затем продолжить цикл.

Кажется, некоторые тенденции можно отфильтровать. Прочитав код самостоятельно, я обнаружил, что объяснение ИИ было очень понятным, даже более понятным, чем если бы я объяснял его сам.
Позволяя ИИ анализировать и объяснять общую стратегию, а затем на основе объяснения ИИ общей стратегии постепенно анализировать, разбирать и объяснять локальные детали стратегии и объяснять идеи дизайна. Полученное нами объяснение было относительно точным. ИИ перечислил почти все детали, предусмотренные в стратегии, без упущений и провел подробный анализ путем дополнительных вопросов. Такой способ изучения всего стратегического мышления, деталей проектирования кода и накопления опыта в разработке стратегий очень полезен.
На пути количественной торговли ИИ может стать для нас чрезвычайно мощным партнером в обучении и росте. Вместо того чтобы полагаться на ИИ для генерации готовых стратегий одним щелчком мыши, ИИ может:
Только этот путь может по-настоящему расширить наши возможности количественной торговли и создать нашу собственную систематическую торговую систему. На платформе количественной торговли Inventor мы можем в полной мере использовать возможности искусственного интеллекта и объединить его с собственной практикой, чтобы двигаться дальше и летать выше.